{
  "library": {
    "version": "3.0.0",
    "name": "@visa/nova-react"
  },
  "components": [
    {
      "name": "accordion",
      "version": "0.0.1",
      "description": "Sets of vertical headers that reveal or hide the accordion panel.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Individual accordions",
          "description": "",
          "order": 1
        },
        {
          "name": "Multi-select accordion groups",
          "description": "",
          "order": 2
        },
        {
          "name": "Single-select accordion groups",
          "description": "",
          "order": 3
        },
        {
          "name": "Custom accordion groups",
          "description": "",
          "order": 4
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/collapsed-accordion",
            "github": "apps/workshop/src/examples/components/accordion/collapsed-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Accordion, AccordionHeading, AccordionPanel, AccordionToggleIcon, Typography } from '@visa/nova-react';\n\nexport const CollapsedAccordion = () => {\n  return (\n    <Accordion>\n      <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n        <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n        Accordion title\n      </AccordionHeading>\n      <AccordionPanel>\n        <Typography>This is required text that describes the accordion section in more detail.</Typography>\n      </AccordionPanel>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Default accordion"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/collapsed-disabled-accordion",
            "github": "apps/workshop/src/examples/components/accordion/collapsed-disabled-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Accordion, AccordionHeading, AccordionPanel, AccordionToggleIcon, Typography } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'collapsed-disabled-accordion';\n\nexport const CollapsedDisabledAccordion = () => {\n  const expanded = false;\n\n  return (\n    <Accordion id={id} tag=\"div\">\n      <AccordionHeading\n        aria-controls={`${id}-accordion-panel`}\n        aria-expanded={expanded}\n        disabled\n        buttonSize=\"large\"\n        colorScheme=\"secondary\"\n        id={`${id}-accordion-header`}\n        tag=\"button\"\n      >\n        <AccordionToggleIcon\n          accordionOpen={expanded}\n          elementClosed={<VisaChevronRightTiny rtl />}\n          elementOpen={<VisaChevronDownTiny />}\n        />\n        Accordion title\n      </AccordionHeading>\n      <AccordionPanel aria-hidden={!expanded} id={`${id}-accordion-panel`}>\n        <Typography>This is required text that describes the accordion section in more detail.</Typography>\n      </AccordionPanel>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Disabled accordion"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/with-icon-accordion",
            "github": "apps/workshop/src/examples/components/accordion/with-icon-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny, VisaCloudLow } from '@visa/nova-icons-react';\nimport { Accordion, AccordionHeading, AccordionPanel, AccordionToggleIcon, Typography } from '@visa/nova-react';\n\nexport const WithIconAccordion = () => {\n  return (\n    <Accordion>\n      <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n        <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n        <VisaCloudLow />\n        Accordion title\n      </AccordionHeading>\n      <AccordionPanel>\n        <Typography>This is required text that describes the accordion section in more detail.</Typography>\n      </AccordionPanel>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Accordion with icon"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/with-badge-accordion",
            "github": "apps/workshop/src/examples/components/accordion/with-badge-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny, VisaSuccessTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Badge,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const WithBadgeAccordion = () => {\n  return (\n    <Accordion>\n      <UtilityFragment vAlignItems=\"center\">\n        <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n          {/* TODO: Remove this style tag after nova-styles fix */}\n          <AccordionToggleIcon\n            elementClosed={<VisaChevronRightTiny rtl />}\n            elementOpen={<VisaChevronDownTiny />}\n            style={{ alignSelf: 'center' }}\n          />\n          Accordion title\n          <UtilityFragment vMarginLeft=\"auto\">\n            <Badge badgeType=\"stable\">\n              <VisaSuccessTiny />\n              Label\n            </Badge>\n          </UtilityFragment>\n        </AccordionHeading>\n      </UtilityFragment>\n      <AccordionPanel>\n        <Typography>This is required text that describes the accordion section in more detail.</Typography>\n      </AccordionPanel>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Accordion with badge"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/subtle-accordion",
            "github": "apps/workshop/src/examples/components/accordion/subtle-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const SubtleAccordion = () => {\n  return (\n    <Accordion>\n      <UtilityFragment vGap={2}>\n        <AccordionHeading\n          className=\"v-typography-body-2-medium\"\n          colorScheme=\"tertiary\"\n          style={\n            {\n              '--v-accordion-foreground-initial': 'var(--palette-default-active)',\n              '--v-button-default-background': 'transparent',\n            } as CSSProperties\n          }\n        >\n          <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n          Accordion title\n        </AccordionHeading>\n      </UtilityFragment>\n      <UtilityFragment vPaddingHorizontal={32}>\n        <AccordionPanel\n          style={\n            {\n              '--v-accordion-panel-background-color': 'transparent',\n              '--v-accordion-panel-border-size': '0px',\n            } as CSSProperties\n          }\n        >\n          <Typography>This is required text that describes the accordion section in more detail.</Typography>\n        </AccordionPanel>\n      </UtilityFragment>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Subtle accordion"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/disabled-subtle-accordion",
            "github": "apps/workshop/src/examples/components/accordion/disabled-subtle-accordion.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-subtle-accordion';\n\nexport const DisabledSubtleAccordion = () => {\n  const expanded = false;\n\n  return (\n    <Accordion tag=\"div\">\n      <UtilityFragment vGap={2}>\n        <AccordionHeading\n          aria-controls={`${id}-accordion-panel`}\n          aria-expanded={expanded}\n          buttonSize=\"large\"\n          disabled\n          colorScheme=\"tertiary\"\n          id={`${id}-accordion-header`}\n          tag=\"button\"\n        >\n          <AccordionToggleIcon\n            accordionOpen={expanded}\n            elementClosed={<VisaChevronRightTiny rtl />}\n            elementOpen={<VisaChevronDownTiny />}\n          />\n          <Typography variant=\"body-2-medium\">Accordion title</Typography>\n        </AccordionHeading>\n      </UtilityFragment>\n      <UtilityFragment vPaddingHorizontal={32}>\n        <AccordionPanel\n          aria-hidden={!expanded}\n          id={`${id}-accordion-panel`}\n          style={\n            {\n              '--v-accordion-panel-background-color': 'transparent',\n              '--v-accordion-panel-border-size': '0px',\n            } as CSSProperties\n          }\n        >\n          <Typography>This is required text that describes the accordion section in more detail.</Typography>\n        </AccordionPanel>\n      </UtilityFragment>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Disabled subtle accordion"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Individual accordions",
          "url": {
            "iframe": "components/accordion/subtle-accordion-with-icon",
            "github": "apps/workshop/src/examples/components/accordion/subtle-accordion-with-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronRightTiny, VisaCloudLow } from '@visa/nova-icons-react';\n\nexport const SubtleAccordionWithIcon = () => {\n  return (\n    <Accordion>\n      <UtilityFragment vGap={2}>\n        <AccordionHeading\n          className=\"v-typography-body-2-medium\"\n          colorScheme=\"tertiary\"\n          style={\n            {\n              '--v-accordion-foreground-initial': 'var(--palette-default-active)',\n              '--v-button-default-background': 'transparent',\n            } as CSSProperties\n          }\n        >\n          <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n          <VisaCloudLow />\n          Accordion title\n        </AccordionHeading>\n      </UtilityFragment>\n      <UtilityFragment vPaddingHorizontal={32}>\n        <AccordionPanel\n          style={\n            {\n              '--v-accordion-panel-background-color': 'transparent',\n              '--v-accordion-panel-border-size': '0px',\n            } as CSSProperties\n          }\n        >\n          <Typography>This is required text that describes the accordion section in more detail.</Typography>\n        </AccordionPanel>\n      </UtilityFragment>\n    </Accordion>\n  );\n};\n"
          },
          "name": "Subtle accordion with icon"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select accordion groups",
          "url": {
            "iframe": "components/accordion/default-multi-select-accordion-group",
            "github": "apps/workshop/src/examples/components/accordion/default-multi-select-accordion-group.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny, VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-multi-select-accordion-group-example';\n\nexport const DefaultMultiSelectAccordionGroup = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`}>\n          <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel>\n            <Typography>{accordion.content}</Typography>\n          </AccordionPanel>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Default multi-select accordion group"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select accordion groups",
          "url": {
            "iframe": "components/accordion/multi-select-accordion-group-with-expanded",
            "github": "apps/workshop/src/examples/components/accordion/multi-select-accordion-group-with-expanded.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-select-accordion-group-with-expanded';\n\nexport const MultiSelectAccordionGroupWithExpanded = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`} open={index === 0}>\n          <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel>\n            <Typography>{accordion.content}</Typography>\n          </AccordionPanel>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Multi-select accordion group with accordion expanded by default"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select accordion groups",
          "url": {
            "iframe": "components/accordion/multi-select-accordion-group-with-disabled",
            "github": "apps/workshop/src/examples/components/accordion/multi-select-accordion-group-with-disabled.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-select-accordion-group-with-disabled';\n\nconst accordions = [\n  {\n    id: `${id}-panel-1`,\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n    disabled: true,\n  },\n  {\n    id: `${id}-panel-2`,\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    id: `${id}-panel-3`,\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\nexport const MultiSelectAccordionGroupWithDisabled = () => {\n  const [expandedPanels, setExpandedPanels] = useState<{\n    [key: string]: boolean;\n  }>({\n    panel1: false,\n    panel2: false,\n    panel3: false,\n  });\n\n  const handleToggle = (panel: string) => {\n    setExpandedPanels(prevState => ({\n      ...prevState,\n      [panel]: !prevState[panel],\n    }));\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => {\n        const panelKey = `panel${index + 1}`;\n\n        return (\n          <Accordion id={accordion.id} tag=\"div\" key={accordion.id}>\n            <AccordionHeading\n              aria-controls={`${accordion.id}-accordion-panel`}\n              aria-expanded={expandedPanels[panelKey]}\n              disabled={accordion.disabled}\n              buttonSize=\"large\"\n              colorScheme=\"secondary\"\n              id={`${accordion.id}-accordion-header`}\n              onClick={() => handleToggle(panelKey)}\n              tag=\"button\"\n            >\n              <AccordionToggleIcon\n                accordionOpen={expandedPanels[panelKey]}\n                elementClosed={<VisaChevronRightTiny rtl />}\n                elementOpen={<VisaChevronDownTiny />}\n              />\n              {accordion.header}\n            </AccordionHeading>\n            <AccordionPanel aria-hidden={!expandedPanels[panelKey]} id={`${accordion.id}-accordion-panel`}>\n              <Typography>{accordion.content}</Typography>\n            </AccordionPanel>\n          </Accordion>\n        );\n      })}\n    </Utility>\n  );\n};\n"
          },
          "name": "Multi-select accordion group with disabled accordion"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select accordion groups",
          "url": {
            "iframe": "components/accordion/subtle-multi-select-accordion-group",
            "github": "apps/workshop/src/examples/components/accordion/subtle-multi-select-accordion-group.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'subtle-multi-select-accordion-group';\n\nexport const SubtleMultiSelectAccordionGroup = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`}>\n          <UtilityFragment vGap={2}>\n            <AccordionHeading\n              className=\"v-typography-body-2-medium\"\n              colorScheme=\"tertiary\"\n              style={\n                {\n                  '--v-accordion-foreground-initial': 'var(--palette-default-active)',\n                  '--v-button-default-background': 'transparent',\n                } as CSSProperties\n              }\n            >\n              <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n              {accordion.header}\n            </AccordionHeading>\n          </UtilityFragment>\n          <UtilityFragment vPaddingHorizontal={32}>\n            <AccordionPanel\n              style={\n                {\n                  '--v-accordion-panel-background-color': 'transparent',\n                  '--v-accordion-panel-border-size': '0px',\n                } as CSSProperties\n              }\n            >\n              <Typography>{accordion.content}</Typography>\n            </AccordionPanel>\n          </UtilityFragment>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Subtle multi-select accordion group"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select accordion groups",
          "url": {
            "iframe": "components/accordion/default-single-select-accordion-group",
            "github": "apps/workshop/src/examples/components/accordion/default-single-select-accordion-group.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-single-select-accordion-group';\n\nexport const DefaultSingleSelectAccordionGroup = () => {\n  const [openIndex, setOpenIndex] = useState(-1);\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`} open={openIndex === index}>\n          <AccordionHeading\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            onClick={event => {\n              event.preventDefault();\n              // If open, close accordion, else open accordion\n              setOpenIndex(openIndex === index ? -1 : index);\n            }}\n          >\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel>\n            <Typography tag=\"span\">{accordion.content}</Typography>\n          </AccordionPanel>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Default single-select accordion group"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select accordion groups",
          "url": {
            "iframe": "components/accordion/single-select-accordion-group-with-expanded",
            "github": "apps/workshop/src/examples/components/accordion/single-select-accordion-group-with-expanded.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'single-select-accordion-group-with-expanded';\n\nexport const SingleSelectAccordionGroupWithExpanded = () => {\n  const [openIndex, setOpenIndex] = useState(0);\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`} open={openIndex === index}>\n          <AccordionHeading\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            onClick={event => {\n              event.preventDefault();\n              // If open, close accordion, else open accordion\n              setOpenIndex(openIndex === index ? -1 : index);\n            }}\n          >\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel>\n            <Typography tag=\"span\">{accordion.content}</Typography>\n          </AccordionPanel>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Single-select accordion group with accordion expanded by default"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select accordion groups",
          "url": {
            "iframe": "components/accordion/subtle-single-select-accordion-group",
            "github": "apps/workshop/src/examples/components/accordion/subtle-single-select-accordion-group.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useState, type CSSProperties } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'subtle-single-select-accordion-group';\n\nexport const SubtleSingleSelectAccordionGroup = () => {\n  const [openIndex, setOpenIndex] = useState(-1);\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`} open={index === openIndex}>\n          <UtilityFragment vGap={2}>\n            <AccordionHeading\n              className=\"v-typography-body-2-medium\"\n              colorScheme=\"tertiary\"\n              onClick={event => {\n                event.preventDefault();\n                // If open, close accordion, else open accordion\n                setOpenIndex(openIndex === index ? -1 : index);\n              }}\n              style={\n                {\n                  '--v-accordion-foreground-initial': 'var(--palette-default-active)',\n                  '--v-button-default-background': 'transparent',\n                } as CSSProperties\n              }\n            >\n              <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n              {accordion.header}\n            </AccordionHeading>\n          </UtilityFragment>\n          <UtilityFragment vPaddingHorizontal={32}>\n            <AccordionPanel\n              style={\n                {\n                  '--v-accordion-panel-background-color': 'transparent',\n                  '--v-accordion-panel-border-size': '0px',\n                } as CSSProperties\n              }\n            >\n              <Typography>{accordion.content}</Typography>\n            </AccordionPanel>\n          </UtilityFragment>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Subtle single-select accordion group"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Custom accordion groups",
          "url": {
            "iframe": "components/accordion/native-single-select-accordion-group",
            "github": "apps/workshop/src/examples/components/accordion/native-single-select-accordion-group.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'native-single-select-accordion-group';\n\nexport const NativeSingleSelectAccordionGroup = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={6}>\n      {accordions.map((accordion, index) => (\n        <Accordion key={`${id}-${index}`} name={id}>\n          <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\">\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel>\n            <Typography tag=\"span\">{accordion.content}</Typography>\n          </AccordionPanel>\n        </Accordion>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Native single-select accordion group"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Custom accordion groups",
          "url": {
            "iframe": "components/accordion/default-with-item-open-accordion",
            "github": "apps/workshop/src/examples/components/accordion/default-with-item-open-accordion.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  useAccordion,\n} from '@visa/nova-react';\nimport { Fragment } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\nexport const DefaultWithItemOpenAccordion = () => {\n  const { isIndexExpanded, toggleIndexExpanded } = useAccordion({ defaultExpanded: 0 });\n\n  return (\n    <Accordion id=\"accordion-default-open-group\" tag=\"div\">\n      {accordions.map((accordion, index) => (\n        <Fragment key={`accordion-default-open-group-${index}`}>\n          <AccordionHeading\n            aria-controls={`accordion-default-open-panel-${index}`}\n            aria-expanded={isIndexExpanded(index)}\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            id={`accordion-default-open-header-${index}`}\n            onClick={() => toggleIndexExpanded(index)}\n            tag=\"button\"\n          >\n            <AccordionToggleIcon\n              accordionOpen={isIndexExpanded(index)}\n              elementClosed={<VisaChevronRightTiny rtl />}\n              elementOpen={<VisaChevronDownTiny />}\n            />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel aria-hidden={!isIndexExpanded(index)} id={`accordion-default-open-panel-${index}`}>\n            <Typography>{accordion.content}</Typography>\n          </AccordionPanel>\n        </Fragment>\n      ))}\n    </Accordion>\n  );\n};\n"
          },
          "name": "Custom single-select accordion group with accordion expanded by default"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Custom accordion groups",
          "url": {
            "iframe": "components/accordion/disclosure-group-accordion",
            "github": "apps/workshop/src/examples/components/accordion/disclosure-group-accordion.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  useAccordion,\n} from '@visa/nova-react';\nimport { Fragment } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\nexport const DisclosureGroupAccordion = () => {\n  const { isIndexExpanded, toggleIndexExpanded } = useAccordion({ defaultExpanded: [0, 1] });\n\n  return (\n    <Accordion id=\"accordion-disclosure-group\" tag=\"div\">\n      {accordions.map((accordion, index) => (\n        <Fragment key={`accordion-disclosure-group-${index}`}>\n          <AccordionHeading\n            aria-controls={`accordion-disclosure-group-panel-${index}`}\n            aria-expanded={isIndexExpanded(index)}\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            id={`accordion-disclosure-group-header-${index}`}\n            onClick={() => toggleIndexExpanded(index)}\n            tag=\"button\"\n          >\n            <AccordionToggleIcon\n              accordionOpen={isIndexExpanded(index)}\n              elementClosed={<VisaChevronRightTiny rtl />}\n              elementOpen={<VisaChevronDownTiny />}\n            />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel aria-hidden={!isIndexExpanded(index)} id={`accordion-disclosure-group-panel-${index}`}>\n            <Typography>{accordion.content}</Typography>\n          </AccordionPanel>\n        </Fragment>\n      ))}\n    </Accordion>\n  );\n};\n"
          },
          "name": "Custom multi-select accordion group with accordion expanded by default"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Custom accordion groups",
          "url": {
            "iframe": "components/accordion/key-nav-group-accordion",
            "github": "apps/workshop/src/examples/components/accordion/key-nav-group-accordion.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  useAccordion,\n} from '@visa/nova-react';\nimport { Fragment } from 'react';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 1',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 2',\n  },\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Accordion title 3',\n  },\n];\n\nexport const KeyNavGroupAccordion = () => {\n  const { isIndexExpanded, onKeyNavigation, ref: accordionRef, toggleIndexExpanded } = useAccordion();\n\n  return (\n    <Accordion id=\"accordion-key-nav-group\" onKeyDown={onKeyNavigation} tag=\"div\">\n      {accordions.map((accordion, i) => (\n        <Fragment key={i}>\n          <AccordionHeading\n            aria-controls={`accordion-key-nav-group-panel-${i}`}\n            aria-expanded={isIndexExpanded(i)}\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            id={`accordion-key-nav-group-header-${i}`}\n            onClick={() => toggleIndexExpanded(i)}\n            ref={el => {\n              accordionRef.current[i] = el;\n            }}\n            tag=\"button\"\n          >\n            <AccordionToggleIcon\n              accordionOpen={isIndexExpanded(i)}\n              elementClosed={<VisaChevronRightTiny rtl />}\n              elementOpen={<VisaChevronDownTiny />}\n            />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel aria-hidden={!isIndexExpanded(i)} id={`accordion-key-nav-group-panel-${i}`}>\n            <Typography>{accordion.content}</Typography>\n          </AccordionPanel>\n        </Fragment>\n      ))}\n    </Accordion>\n  );\n};\n"
          },
          "name": "Accordion group with arrow key navigation"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Custom accordion groups",
          "url": {
            "iframe": "components/accordion/reusable",
            "github": "apps/workshop/src/examples/components/accordion/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny, VisaCloudLow, VisaSuccessTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Badge,\n  Button,\n  Checkbox,\n  Input,\n  InputContainer,\n  Label,\n  Typography,\n  Utility,\n  UtilityFragment,\n  type AccordionProperties,\n} from '@visa/nova-react';\nimport { type CSSProperties, type ReactNode, useId, useState } from 'react';\n\n// Nova Accordion Component Props\n// Note: Omit 'prefix' because it's a native HTML attribute on <details> that expects a string,\n// but we're overriding it to accept ReactNode for icon/badge support\nexport type NovaAccordionProps = Omit<AccordionProperties, 'prefix'> & {\n  description?: string;\n  disabled?: boolean;\n  padding?: boolean;\n  prefix?: ReactNode;\n  showIcon?: boolean;\n  subtle?: boolean;\n  suffix?: ReactNode;\n  title?: string;\n  toggleIcon?: ReactNode;\n};\n\n// Main Nova Accordion Component\nexport const NovaAccordion = ({\n  children,\n  description,\n  disabled = false,\n  id: idProp,\n  name,\n  padding = true,\n  prefix,\n  showIcon = true,\n  subtle = false,\n  suffix,\n  title,\n  toggleIcon,\n  ...remainingProps\n}: NovaAccordionProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  return (\n    <Accordion id={id} name={name ?? undefined} {...remainingProps}>\n      <UtilityFragment vGap={2}>\n        <AccordionHeading\n          buttonSize={subtle ? undefined : 'large'}\n          className=\"v-typography-body-2-medium\"\n          colorScheme={subtle ? 'tertiary' : 'secondary'}\n          disabled={disabled}\n          style={\n            subtle\n              ? ({\n                  '--v-accordion-foreground-initial': 'var(--palette-default-active)',\n                  '--v-button-default-background': 'transparent',\n                } as CSSProperties)\n              : undefined\n          }\n        >\n          {toggleIcon}\n          {showIcon && (\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n          )}\n          {prefix}\n          {title && (\n            <Utility vFlex vAlignItems=\"center\" vGap=\"6\">\n              {title}\n            </Utility>\n          )}\n          {suffix}\n        </AccordionHeading>\n      </UtilityFragment>\n      <UtilityFragment vPaddingHorizontal={padding ? 32 : undefined}>\n        <AccordionPanel\n          style={\n            subtle\n              ? ({\n                  '--v-accordion-panel-background-color': 'transparent',\n                  '--v-accordion-panel-border-size': '0px',\n                } as CSSProperties)\n              : undefined\n          }\n        >\n          {description && <Typography>{description}</Typography>}\n          {children}\n        </AccordionPanel>\n      </UtilityFragment>\n    </Accordion>\n  );\n};\n\n// export default NovaAccordion;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  accordions: number;\n  description: string;\n  disabled: boolean;\n  multiselect: boolean;\n  padding: boolean;\n  showBadge: boolean;\n  showIcon: boolean;\n  showToggleIcon: boolean;\n  subtle: boolean;\n  title: string;\n}\n\n// Demo Component\nexport const NovaAccordionDemo = () => {\n  const name = 'reusable-accordion-demo';\n\n  const defaultCustomizations: DemoCustomizations = {\n    accordions: 1,\n    description: 'This is required text that describes the accordion in more detail.',\n    disabled: false,\n    multiselect: false,\n    padding: true,\n    showBadge: false,\n    showIcon: false,\n    showToggleIcon: true,\n    subtle: false,\n    title: 'Success title',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const accordions = Array.from({ length: Math.max(1, Math.floor(customizations.accordions)) }, (_, i) => i);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean | number) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <Utility vFlex vFlexCol vGap={6}>\n        {accordions.map(i => (\n          <NovaAccordion\n            key={`reusable-accordion-${i}`}\n            description={customizations.description || ''}\n            disabled={customizations.disabled}\n            name={customizations.multiselect ? undefined : name}\n            padding={customizations.padding}\n            showIcon={customizations.showToggleIcon}\n            subtle={customizations.subtle}\n            title={`${customizations.title || ''} ${i + 1}`}\n            prefix={customizations.showIcon ? <VisaCloudLow /> : undefined}\n            suffix={\n              customizations.showBadge ? (\n                <Badge badgeType=\"stable\" style={{ marginLeft: 'auto' }}>\n                  <VisaSuccessTiny style={{ margin: 0 }} />\n                  <span>Label</span>\n                </Badge>\n              ) : undefined\n            }\n          />\n        ))}\n      </Utility>\n\n      <div style={{ marginTop: '24px' }} />\n\n      <NovaAccordion title=\"Customize demo\">\n        <form onSubmit={handleApply}>\n          <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n            <div>\n              <Label htmlFor=\"accordions\">Accordions</Label>\n              <InputContainer>\n                <Input\n                  id=\"accordions\"\n                  type=\"number\"\n                  value={formValues.accordions}\n                  onChange={e => handleInputChange('accordions', parseInt(e.target.value) || 1)}\n                />\n              </InputContainer>\n            </div>\n\n            <div>\n              <Label htmlFor=\"description\">Description</Label>\n              <InputContainer>\n                <Input\n                  id=\"description\"\n                  type=\"text\"\n                  value={formValues.description}\n                  onChange={e => handleInputChange('description', e.target.value)}\n                />\n              </InputContainer>\n            </div>\n\n            <div>\n              <Label htmlFor=\"title\">Title</Label>\n              <InputContainer>\n                <Input\n                  id=\"title\"\n                  type=\"text\"\n                  value={formValues.title}\n                  onChange={e => handleInputChange('title', e.target.value)}\n                />\n              </InputContainer>\n            </div>\n\n            <Label>\n              <Checkbox checked={formValues.disabled} onChange={e => handleInputChange('disabled', e.target.checked)} />\n              Disabled\n            </Label>\n\n            <Label>\n              <Checkbox\n                checked={formValues.multiselect}\n                onChange={e => handleInputChange('multiselect', e.target.checked)}\n              />\n              Multiselect\n            </Label>\n\n            <Label>\n              <Checkbox checked={formValues.padding} onChange={e => handleInputChange('padding', e.target.checked)} />\n              Padding\n            </Label>\n\n            <Label>\n              <Checkbox\n                checked={formValues.showBadge}\n                onChange={e => handleInputChange('showBadge', e.target.checked)}\n              />\n              Show badge\n            </Label>\n\n            <Label>\n              <Checkbox checked={formValues.showIcon} onChange={e => handleInputChange('showIcon', e.target.checked)} />\n              Show icon\n            </Label>\n\n            <Label>\n              <Checkbox\n                checked={formValues.showToggleIcon}\n                onChange={e => handleInputChange('showToggleIcon', e.target.checked)}\n              />\n              Show toggle icon\n            </Label>\n\n            <Label>\n              <Checkbox checked={formValues.subtle} onChange={e => handleInputChange('subtle', e.target.checked)} />\n              Subtle\n            </Label>\n          </Utility>\n\n          <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n            <Button type=\"submit\">Apply</Button>\n            <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n              Reset\n            </Button>\n          </Utility>\n        </form>\n      </NovaAccordion>\n    </div>\n  );\n};\n\nexport default NovaAccordionDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable accordion"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Accordion",
          "selector": "<Accordion />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Sets of vertical headers that reveal or hide the accordion panel."
        },
        {
          "order": 2,
          "name": "Accordionheading",
          "selector": "<AccordionHeading />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Default summary element, styled as a button that is used to expand and collapse content."
        },
        {
          "order": 3,
          "name": "Accordionpanel",
          "selector": "<AccordionPanel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component containing the content of the accordion."
        },
        {
          "order": 4,
          "name": "Accordiontoggleicon",
          "selector": "<AccordionToggleIcon />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component containing the icon and logic for the accordion toggle icon."
        },
        {
          "order": 5,
          "name": "useAccordion",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to manage the open state and keyboard navigation of accordions."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Accordion",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "details",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "Accordionheading",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "Accordionheading",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "colorScheme",
          "section": "Accordionheading",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "Accordionheading",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "iconButton",
          "section": "Accordionheading",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "Accordionheading",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "Accordionheading",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "Accordionheading",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "Accordionheading",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "summary",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "tag",
          "section": "Accordionpanel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "accordionOpen",
          "section": "Accordiontoggleicon",
          "data": {
            "name": "accordionOpen",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "manually assign the open state of the accordion"
          }
        },
        {
          "name": "elementClosed",
          "section": "Accordiontoggleicon",
          "data": {
            "name": "elementClosed",
            "type": "ReactElement",
            "default": "<VisaChevronRightTiny rtl />",
            "required": "false",
            "description": "The icon in closed state"
          }
        },
        {
          "name": "elementOpen",
          "section": "Accordiontoggleicon",
          "data": {
            "name": "elementOpen",
            "type": "ReactElement",
            "default": "<VisaChevronDownTiny />",
            "required": "false",
            "description": "The icon in the open state"
          }
        }
      ]
    },
    {
      "name": "anchor-link-menu",
      "version": "0.0.1",
      "description": "Menu of links that navigate to sections within the current page.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default anchor link menus",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default anchor link menus",
          "url": {
            "iframe": "components/anchor-link-menu/default-anchor-link-menu",
            "github": "apps/workshop/src/examples/components/anchor-link-menu/default-anchor-link-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { AnchorLinkMenu, AnchorLinkMenuHeader, Link, Typography } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-anchor-link-menu';\n\nexport const DefaultAnchorLinkMenu = () => {\n\n  return (\n    <AnchorLinkMenu aria-labelledby={`${id}-header`}>\n      <section>\n        <AnchorLinkMenuHeader>\n          <Typography id={`${id}-header`} tag=\"h2\" variant=\"overline\">\n            Section title\n          </Typography>\n        </AnchorLinkMenuHeader>\n        <ul>\n          <li>\n            <Link aria-current=\"true\" href=\"./anchor-link-menu\">\n              L1 label 1\n            </Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 2</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 3</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 4</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 5</Link>\n          </li>\n        </ul>\n      </section>\n    </AnchorLinkMenu>\n  );\n};\n"
          },
          "name": "Default anchor link menu"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default anchor link menus",
          "url": {
            "iframe": "components/anchor-link-menu/no-title-anchor-link-menu",
            "github": "apps/workshop/src/examples/components/anchor-link-menu/no-title-anchor-link-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { AnchorLinkMenu, Link } from '@visa/nova-react';\n\nexport const NoTitleAnchorLinkMenu = () => {\n  return (\n    <AnchorLinkMenu aria-label=\"Section title\">\n      <section>\n        <ul>\n          <li>\n            <Link aria-current=\"true\" href=\"./anchor-link-menu\">\n              L1 label 1\n            </Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 2</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 3</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 4</Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 5</Link>\n          </li>\n        </ul>\n      </section>\n    </AnchorLinkMenu>\n  );\n};\n"
          },
          "name": "Anchor link menu without section title"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default anchor link menus",
          "url": {
            "iframe": "components/anchor-link-menu/nested-anchor-link-menu",
            "github": "apps/workshop/src/examples/components/anchor-link-menu/nested-anchor-link-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { AnchorLinkMenu, AnchorLinkMenuHeader, Link, Typography } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nested-anchor-link-menu';\n\nexport const NestedAnchorLinkMenu = () => {\n  return (\n    <AnchorLinkMenu aria-labelledby={`${id}-header`}>\n      <section>\n        <AnchorLinkMenuHeader>\n          <Typography id={`${id}-header`} tag=\"h2\" variant=\"overline\">\n            Section title\n          </Typography>\n        </AnchorLinkMenuHeader>\n        <ul>\n          <li>\n            <Link aria-current=\"true\" href=\"./anchor-link-menu\">\n              L1 label 1\n            </Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 2</Link>\n            <ul>\n              <li>\n                <Link href=\"./anchor-link-menu\">L2 label 1</Link>\n              </li>\n              <li>\n                <Link href=\"./anchor-link-menu\">L2 label 2</Link>\n              </li>\n            </ul>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 3</Link>\n          </li>\n        </ul>\n      </section>\n    </AnchorLinkMenu>\n  );\n};\n"
          },
          "name": "Anchor link menu with nested items"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default anchor link menus",
          "url": {
            "iframe": "components/anchor-link-menu/direction-rtl-anchor-link-menu",
            "github": "apps/workshop/src/examples/components/anchor-link-menu/direction-rtl-anchor-link-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { AnchorLinkMenu, AnchorLinkMenuHeader, Link, Typography } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'rtl-anchor-link-menu';\n\nexport const DirectionRTLAnchorLinkMenu = () => {\n  return (\n    <AnchorLinkMenu aria-labelledby={`${id}-header`} dir=\"rtl\">\n      <section>\n        <AnchorLinkMenuHeader>\n          <Typography id={`${id}-header`} tag=\"h2\" variant=\"overline\">\n            Section title\n          </Typography>\n        </AnchorLinkMenuHeader>\n        <ul>\n          <li>\n            <Link aria-current=\"true\" href=\"./anchor-link-menu\">\n              L1 label 1\n            </Link>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 2</Link>\n            <ul>\n              <li>\n                <Link href=\"./anchor-link-menu\">L2 label 1</Link>\n              </li>\n              <li>\n                <Link href=\"./anchor-link-menu\">L2 label 2</Link>\n              </li>\n            </ul>\n          </li>\n          <li>\n            <Link href=\"./anchor-link-menu\">L1 label 3</Link>\n          </li>\n        </ul>\n      </section>\n    </AnchorLinkMenu>\n  );\n};\n"
          },
          "name": "Right to left anchor link menu"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Anchorlinkmenu",
          "selector": "<AnchorLinkMenu />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Menu of links that navigate to sections within the current page."
        },
        {
          "order": 2,
          "name": "Anchorlinkmenuheader",
          "selector": "<AnchorLinkMenuHeader />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component containing the header of the anchor link menu."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Anchorlinkmenu",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "aside",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Anchorlinkmenuheader",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "avatar",
      "version": "0.0.1",
      "description": "Icons and/or text representing users or entities.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Small avatars",
          "description": "",
          "order": 1
        },
        {
          "name": "Large avatars",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom avatars",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Small avatars",
          "url": {
            "iframe": "components/avatar/small-image-avatar",
            "github": "apps/workshop/src/examples/components/avatar/small-image-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\nconst user = 'Alex Miller';\n\nexport const SmallImageAvatar = () => {\n  return <Avatar<'img'> alt={user} small tag=\"img\" src={BASE_URL + '/alex-miller-stock.png'} />;\n};\n"
          },
          "name": "Small image avatar"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Small avatars",
          "url": {
            "iframe": "components/avatar/small-initials-avatar",
            "github": "apps/workshop/src/examples/components/avatar/small-initials-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar } from '@visa/nova-react';\n\nconst user = 'Alex Miller';\nconst userInitials = 'AM';\n\nexport const SmallInitialsAvatar = () => {\n  return (\n    <Avatar role=\"img\" aria-label={user} small>\n      {userInitials}\n    </Avatar>\n  );\n};\n"
          },
          "name": "Small initials avatar"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Small avatars",
          "url": {
            "iframe": "components/avatar/small-horizontal-icon-avatar",
            "github": "apps/workshop/src/examples/components/avatar/small-horizontal-icon-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountLow, VisaChevronDownLow, VisaChevronUpLow } from '@visa/nova-icons-react';\nimport { Avatar, Button, DropdownMenu, TabSuffix, Tab, UtilityFragment } from '@visa/nova-react';\nimport { useState, type CSSProperties } from 'react';\nimport { offset, useClick, useFloating, useInteractions } from '@floating-ui/react';\n\nexport const SmallHorizontalIconAvatar = () => {\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n\n  const onToggleAccountMenu = () => setAccountMenuOpen(!accountMenuOpen);\n\n  // TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\n  const id = 'horizontal-advanced-nav';\n\n  // For dropdown menu in the horizontal nav, we use floating UI to open it up\n  const { context, floatingStyles, refs } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-start',\n  });\n  const { getReferenceProps, getFloatingProps } = useInteractions([useClick(context)]);\n\n  return (\n    <div style={{ blockSize: '175px' }}>\n      <Tab tag=\"div\">\n        <Button\n          aria-expanded={accountMenuOpen}\n          aria-label=\"Alex Miller\"\n          element={<Avatar tag=\"button\" />}\n          buttonSize=\"large\"\n          colorScheme=\"tertiary\"\n          ref={refs.setReference}\n          {...getReferenceProps({ onClick: onToggleAccountMenu })}\n        >\n          <VisaAccountLow />\n          <TabSuffix element={accountMenuOpen ? <VisaChevronUpLow /> : <VisaChevronDownLow />} />\n        </Button>\n        {accountMenuOpen && (\n          <UtilityFragment vFlex vFlexCol vPadding={4}>\n            <DropdownMenu\n              id={`${id}-account-menu`}\n              ref={refs.setFloating}\n              style={\n                {\n                  inlineSize: '180px',\n                  maxInlineSize: '100%',\n                  '--v-surface-padding': '8px',\n                  ...floatingStyles,\n                } as CSSProperties\n              }\n              {...getFloatingProps()}\n            >\n              <UtilityFragment vFlex vJustifyContent=\"start\" vPaddingHorizontal={8} vPaddingVertical={11}>\n                <Button<'a'> buttonSize=\"large\" colorScheme=\"tertiary\" tag=\"a\" href=\"./avatar\">\n                  L2 label 1\n                </Button>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"start\" vPaddingHorizontal={8} vPaddingVertical={11}>\n                <Button<'a'> buttonSize=\"large\" colorScheme=\"tertiary\" tag=\"a\" href=\"./avatar\">\n                  L2 label 2\n                </Button>\n              </UtilityFragment>\n            </DropdownMenu>\n          </UtilityFragment>\n        )}\n      </Tab>\n    </div>\n  );\n};\n"
          },
          "name": "Small horizontal icon avatar"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Small avatars",
          "url": {
            "iframe": "components/avatar/small-vertical-icon-avatar",
            "github": "apps/workshop/src/examples/components/avatar/small-vertical-icon-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { Button, Nav, Tabs, Tab, TabSuffix } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const SmallVerticalIconAvatar = () => {\n  const [accountIsOpen, setAccountIsOpen] = useState(false);\n\n  return (\n    <Nav aria-label=\"Vertical nav with active page\" orientation=\"vertical\" tag=\"div\">\n      <Tabs orientation=\"vertical\" tag=\"div\">\n        <Tab tag=\"div\">\n          <Button\n            aria-expanded={accountIsOpen}\n            aria-label=\"Alex Miller\"\n            buttonSize=\"large\"\n            colorScheme=\"tertiary\"\n            onClick={() => setAccountIsOpen(!accountIsOpen)}\n          >\n            <VisaAccountTiny />\n            <TabSuffix element={<VisaChevronDownTiny />} />\n          </Button>\n        </Tab>\n        {accountIsOpen && (\n          <div>\n            <Tab role=\"none\">\n              <Button\n                aria-current=\"page\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./nav\">L2 label 1</a>}\n                role=\"tab\"\n              />\n            </Tab>\n            <Tab role=\"none\">\n              <Button\n                aria-selected=\"false\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./nav\">L2 label 2</a>}\n                role=\"tab\"\n              />\n            </Tab>\n          </div>\n        )}\n      </Tabs>\n    </Nav>\n  );\n};\n"
          },
          "name": "Small vertical icon avatar"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Large avatars",
          "url": {
            "iframe": "components/avatar/large-image-avatar",
            "github": "apps/workshop/src/examples/components/avatar/large-image-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\nconst user = 'Alex Miller';\n\nexport const LargeImageAvatar = () => {\n  return <Avatar<'img'> alt={user} tag=\"img\" src={BASE_URL + '/alex-miller-stock.png'} />;\n};\n"
          },
          "name": "Large image avatar"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Large avatars",
          "url": {
            "iframe": "components/avatar/large-initials-avatar",
            "github": "apps/workshop/src/examples/components/avatar/large-initials-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar } from '@visa/nova-react';\n\nconst user = 'Alex Miller';\nconst userInitials = 'AM';\n\nexport const LargeInitialsAvatar = () => {\n  return <Avatar role=\"img\" aria-label={user}>{userInitials}</Avatar>;\n};\n"
          },
          "name": "Large initials avatar"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Large avatars",
          "url": {
            "iframe": "components/avatar/large-icon-avatar",
            "github": "apps/workshop/src/examples/components/avatar/large-icon-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar } from '@visa/nova-react';\nimport { VisaAccountLow } from '@visa/nova-icons-react';\n\nconst user = 'Alex Miller';\n\nexport const LargeIconAvatar = () => {\n  return (\n    <Avatar aria-label={user} role=\"img\">\n      <VisaAccountLow />\n    </Avatar>\n  );\n};\n"
          },
          "name": "Large icon avatar"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Large avatars",
          "url": {
            "iframe": "components/avatar/fictitious-brand-avatar",
            "github": "apps/workshop/src/examples/components/avatar/fictitious-brand-avatar.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\nimport { Avatar } from '@visa/nova-react';\n\nexport const FictitiousBrandAvatar = () => {\n  return (\n    <Avatar\n      role=\"img\"\n      aria-label=\"Brand\"\n      className=\"fictitious-brand\"\n      style={\n        {\n          '--v-avatar-background': '#6ef2fb',\n          '--v-avatar-foreground': 'var(--palette-default-text)',\n          '--typography-body-2-font-weight': 800,\n        } as CSSProperties\n      }\n    >\n      B\n    </Avatar>\n  );\n};\n"
          },
          "name": "Large ficticious brand avatar"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Custom avatars",
          "url": {
            "iframe": "components/avatar/avatar-as-button",
            "github": "apps/workshop/src/examples/components/avatar/avatar-as-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar, Button, Badge } from '@visa/nova-react';\nimport { VisaAccountLow } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'avatar-as-a-button';\n\nexport const AvatarAsButton = () => {\n  return (\n    <Button\n      element={<Avatar tag=\"button\" />}\n      aria-label=\"Notifications\"\n      aria-describedby={`${id}-notifications-count`}\n      buttonSize=\"large\"\n      colorScheme=\"tertiary\"\n    >\n      <VisaAccountLow />\n      <Badge id={`${id}-notifications-count`} tag=\"sup\" badgeVariant=\"number\">\n        3\n      </Badge>\n    </Button>\n  );\n};\n"
          },
          "name": "Avatar as button"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Avatar",
          "selector": "<Avatar />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Icons and/or text representing users or entities."
        },
        {
          "order": 2,
          "name": "Tabsuffix",
          "selector": "<TabSuffix />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Utility class for positioning and styling elements at the end of tab components."
        }
      ],
      "properties": [
        {
          "name": "small",
          "section": "Avatar",
          "data": {
            "name": "small",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Small Avatar"
          }
        },
        {
          "name": "tag",
          "section": "Avatar",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "span",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "children",
          "section": "Tabsuffix",
          "data": {
            "name": "children",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Child element that the styles are applies to. Only allows for single child element. (not compatible with element property)"
          }
        },
        {
          "name": "element",
          "section": "Tabsuffix",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with children)"
          }
        }
      ]
    },
    {
      "name": "badge",
      "version": "0.0.1",
      "description": "Visual indicators communicating the status of a component.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Subtle badges",
          "description": "",
          "order": 1
        },
        {
          "name": "Neutral badges",
          "description": "",
          "order": 2
        },
        {
          "name": "Positive badges",
          "description": "",
          "order": 3
        },
        {
          "name": "Warning badges",
          "description": "",
          "order": 4
        },
        {
          "name": "Negative badges",
          "description": "",
          "order": 5
        },
        {
          "name": "Number badges",
          "description": "",
          "order": 6
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle badges",
          "url": {
            "iframe": "components/badge/subtle-badge-default",
            "github": "apps/workshop/src/examples/components/badge/subtle-badge-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const SubtleBadgeDefault = () => {\n  return (\n      <Badge badgeType=\"subtle\">\n        <VisaHistoryTiny aria-label=\"history\" /> Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Default subtle badge"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle badges",
          "url": {
            "iframe": "components/badge/subtle-badge-without-icon",
            "github": "apps/workshop/src/examples/components/badge/subtle-badge-without-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge} from '@visa/nova-react';\n\nexport const SubtleBadgeWithoutIcon = () => {\n  return (\n      <Badge badgeType=\"subtle\">\n         Label\n      </Badge>\n        );\n    };"
          },
          "name": "Subtle badge without icon"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle badges",
          "url": {
            "iframe": "components/badge/subtle-badge-with-indicator",
            "github": "apps/workshop/src/examples/components/badge/subtle-badge-with-indicator.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const SubtleBadgeWithIndicator = () => {\n  return (\n      <Badge badgeType=\"subtle\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Subtle badge with indicator"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle badges",
          "url": {
            "iframe": "components/badge/subtle-badge-without-background",
            "github": "apps/workshop/src/examples/components/badge/subtle-badge-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const SubtleBadgeWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"subtle\" clear={true}>\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Subtle badge without background"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-default",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NeutralBadgeDefault = () => {\n  return (\n      <Badge badgeType=\"neutral\">\n        <VisaInformationTiny aria-label=\"information\" /> Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Default neutral badge"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-without-icon",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-without-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge} from '@visa/nova-react';\n\nexport const NeutralBadgeWithoutIcon = () => {\nreturn (\n    <Badge badgeType=\"neutral\" aria-label=\"information\">\n        Label\n    </Badge>\n  );\n};"
          },
          "name": "Neutral badge without icon"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-with-indicator",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-with-indicator.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const NeutralBadgeWithIndicator = () => {\n  return (\n      <Badge badgeType=\"neutral\" aria-label=\"information\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Neutral badge with indicator"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-without-background",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const NeutralBadgeWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"neutral\" clear={true} aria-label=\"information\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Neutral badge without background"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-icon",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NeutralBadgeIcon = () => {\n  return (\n      <Badge badgeType=\"neutral\" badgeVariant=\"icon\">\n        <VisaInformationTiny aria-label=\"information\" /> \n      </Badge>\n  );\n};\n"
          },
          "name": "Neutral icon badge"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Neutral badges",
          "url": {
            "iframe": "components/badge/neutral-badge-icon-without-background",
            "github": "apps/workshop/src/examples/components/badge/neutral-badge-icon-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NeutralBadgeWithIconWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"neutral\" badgeVariant=\"icon\" clear={true}>\n        <VisaInformationTiny aria-label=\"information\" /> \n      </Badge>\n  );\n};"
          },
          "name": "Neutral badge icon without background"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-default",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSuccessTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const PositiveBadgeDefault = () => {\n  return (\n      <Badge badgeType=\"stable\">\n        <VisaSuccessTiny aria-label=\"success\" /> Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Default positive badge"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-without-icon",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-without-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge} from '@visa/nova-react';\n\nexport const PositiveBadgeWithoutIcon = () => {\nreturn (\n    <Badge badgeType=\"stable\" aria-label=\"success\">\n        Label\n    </Badge>\n  );\n};"
          },
          "name": "Positive badge without icon"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-with-indicator",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-with-indicator.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const PositiveBadgeWithIndicator = () => {\n  return (\n      <Badge badgeType=\"stable\" aria-label=\"success\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Positive badge with indicator"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-without-background",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const PositiveBadgeWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"stable\" clear={true} aria-label=\"success\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Positive badge without background"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-icon",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCheckmarkTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const PositiveBadgeIcon = () => {\n  return (\n      <Badge badgeType=\"stable\" badgeVariant=\"icon\">\n        <VisaCheckmarkTiny aria-label=\"success\" /> \n      </Badge>\n  );\n};\n"
          },
          "name": "Positive icon badge with background"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Positive badges",
          "url": {
            "iframe": "components/badge/positive-badge-icon-without-background",
            "github": "apps/workshop/src/examples/components/badge/positive-badge-icon-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCheckmarkTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const PositiveBadgeWithIconWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"stable\" badgeVariant=\"icon\" clear={true}>\n        <VisaCheckmarkTiny aria-label=\"success\" /> \n      </Badge>\n  );\n};"
          },
          "name": "Positive icon badge without background"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-default",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaWarningTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const WarningBadgeDefault = () => {\n  return (\n      <Badge badgeType=\"warning\">\n        <VisaWarningTiny aria-label=\"warning\" /> Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Default warning badge"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-without-icon",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-without-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge} from '@visa/nova-react';\n\nexport const WarningBadgeWithoutIcon = () => {\nreturn (\n    <Badge badgeType=\"warning\" aria-label=\"warning\">\n        Label\n    </Badge>\n  );\n};"
          },
          "name": "Warning badge without icon"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-with-indicator",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-with-indicator.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const WarningBadgeWithIndicator = () => {\n  return (\n      <Badge badgeType=\"warning\" aria-label=\"warning\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Warning badge with indicator"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-without-background",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const WarningBadgeWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"warning\" clear={true} aria-label=\"warning\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Warning badge without background"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-icon",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaWarningTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const WarningBadgeIcon = () => {\n  return (\n      <Badge badgeType=\"warning\" badgeVariant=\"icon\">\n        <VisaWarningTiny aria-label=\"warning\" /> \n      </Badge>\n  );\n};\n"
          },
          "name": "Warning icon badge with background"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Warning badges",
          "url": {
            "iframe": "components/badge/warning-badge-icon-without-background",
            "github": "apps/workshop/src/examples/components/badge/warning-badge-icon-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaWarningTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const WarningBadgeWithIconWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"warning\" badgeVariant=\"icon\" clear={true}>\n        <VisaWarningTiny aria-label=\"warning\" /> \n      </Badge>\n  );\n};"
          },
          "name": "Warning icon badge without background"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-default",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NegativeBadgeDefault = () => {\n  return (\n      <Badge badgeType=\"critical\">\n        <VisaErrorTiny aria-label=\"error\" /> Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Default negative badge"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-without-icon",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-without-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge} from '@visa/nova-react';\n\nexport const NegativeBadgeWithoutIcon = () => {\nreturn (\n    <Badge badgeType=\"critical\" aria-label=\"error\">\n        Label\n    </Badge>\n  );\n};"
          },
          "name": "Negative badge without icon"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-with-indicator",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-with-indicator.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const NegativeBadgeWithIndicator = () => {\n  return (\n      <Badge badgeType=\"critical\" aria-label=\"error\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Negative badge with indicator"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-without-background",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, BadgeEllipse } from '@visa/nova-react';\n\nexport const NegativeBadgeWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"critical\" clear={true} aria-label=\"error\">\n        <BadgeEllipse />\n        Label\n      </Badge>\n  );\n};\n"
          },
          "name": "Negative badge without background"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-icon",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorAltTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NegativeBadgeIcon = () => {\n  return (\n      <Badge badgeType=\"critical\" badgeVariant=\"icon\">\n        <VisaErrorAltTiny aria-label=\"error\" /> \n      </Badge>\n  );\n};\n"
          },
          "name": "Negative icon badge with background"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Negative badges",
          "url": {
            "iframe": "components/badge/negative-badge-icon-without-background",
            "github": "apps/workshop/src/examples/components/badge/negative-badge-icon-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorAltTiny } from '@visa/nova-icons-react';\nimport { Badge } from '@visa/nova-react';\n\nexport const NegativeBadgeWithIconWithoutBackground = () => {\n  return (\n      <Badge badgeType=\"critical\" badgeVariant=\"icon\" clear={true}>\n        <VisaErrorAltTiny aria-label=\"error\" /> \n      </Badge>\n  );\n};"
          },
          "name": "Negative icon badge without background"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Number badges",
          "url": {
            "iframe": "components/badge/badge-number-default",
            "github": "apps/workshop/src/examples/components/badge/badge-number-default.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge } from '@visa/nova-react';\n\nexport const BadgeNumberDefault = () => {\n  return <Badge badgeType=\"critical\" badgeVariant=\"number\">3</Badge>;\n};\n"
          },
          "name": "Short number badge with background"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Number badges",
          "url": {
            "iframe": "components/badge/badge-number-without-background",
            "github": "apps/workshop/src/examples/components/badge/badge-number-without-background.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge } from '@visa/nova-react';\n\nexport const BadgeNumberWithoutBackground = () => {\n  return <Badge badgeType=\"critical\" badgeVariant=\"number\" clear={true}>3</Badge>;\n};"
          },
          "name": "Short number badge without background"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Number badges",
          "url": {
            "iframe": "components/badge/badge-number-long",
            "github": "apps/workshop/src/examples/components/badge/badge-number-long.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge } from '@visa/nova-react';\n\nexport const BadgeNumberLong = () => {\n  return <Badge badgeType=\"critical\" badgeVariant=\"number\">12345</Badge>;\n};\n"
          },
          "name": "Long number badge"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Badge",
          "selector": "<Badge />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Visual indicators communicating the status of a component."
        }
      ],
      "properties": [
        {
          "name": "active",
          "section": "Badge",
          "data": {
            "name": "active",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Active style"
          }
        },
        {
          "name": "badgeType",
          "section": "Badge",
          "data": {
            "name": "badgeType",
            "type": "\"subtle\" , \"critical\" , \"neutral\" , \"stable\" , \"warning\"",
            "default": "",
            "required": "false",
            "description": "Type of Badge"
          }
        },
        {
          "name": "badgeVariant",
          "section": "Badge",
          "data": {
            "name": "badgeVariant",
            "type": "\"number\" , \"icon\"",
            "default": "",
            "required": "false",
            "description": "Variant of Badge"
          }
        },
        {
          "name": "clear",
          "section": "Badge",
          "data": {
            "name": "clear",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Clear background"
          }
        },
        {
          "name": "tag",
          "section": "Badge",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "banner",
      "version": "0.0.1",
      "description": "Messages indicating the global status of an application or website.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Informational banners",
          "description": "",
          "order": 1
        },
        {
          "name": "Success banners",
          "description": "",
          "order": 2
        },
        {
          "name": "Warning banners",
          "description": "",
          "order": 3
        },
        {
          "name": "Error banners",
          "description": "",
          "order": 4
        },
        {
          "name": "Custom banners",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/empty-information-banner",
            "github": "apps/workshop/src/examples/components/banner/empty-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Banner } from '@visa/nova-react';\n\nexport const EmptyInformationBanner = () => {\n  return <Banner></Banner>;\n};\n"
          },
          "name": "Empty informational banner"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/default-information-banner",
            "github": "apps/workshop/src/examples/components/banner/default-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const DefaultInformationBanner = () => {\n  return (\n    <Banner>\n      <MessageIcon />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Default informational banner"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/title-information-banner",
            "github": "apps/workshop/src/examples/components/banner/title-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const TitleInformationBanner = () => {\n  return (\n    <Banner>\n      <MessageIcon />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography variant=\"body-2-bold\">Informational title</Typography>\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Informational banner with title"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/link-information-banner",
            "github": "apps/workshop/src/examples/components/banner/link-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Link, Typography } from '@visa/nova-react';\n\nexport const LinkInformationBanner = () => {\n  return (\n    <Banner>\n      <MessageIcon />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Link href=\"./banner\">Destination label</Link>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Informational banner with link"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/button-information-banner",
            "github": "apps/workshop/src/examples/components/banner/button-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Button, Typography } from '@visa/nova-react';\n\nexport const ButtonInformationBanner = () => {\n  return (\n    <Banner>\n      <MessageIcon />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Informational banner with button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Informational banners",
          "url": {
            "iframe": "components/banner/persistent-information-banner",
            "github": "apps/workshop/src/examples/components/banner/persistent-information-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Banner, BannerContent, Typography } from '@visa/nova-react';\n\nexport const PersistentInformationBanner = () => {\n  return (\n    <Banner>\n      <MessageIcon />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n    </Banner>\n  );\n};\n"
          },
          "name": "Informational banner without close icon button"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/empty-success-banner",
            "github": "apps/workshop/src/examples/components/banner/empty-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Banner } from '@visa/nova-react';\n\nexport const EmptySuccessBanner = () => {\n  return <Banner messageType=\"success\"></Banner>;\n};\n"
          },
          "name": "Empty success banner"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/default-success-banner",
            "github": "apps/workshop/src/examples/components/banner/default-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const DefaultSuccessBanner = () => {\n  return (\n    <Banner messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Default success banner"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/title-success-banner",
            "github": "apps/workshop/src/examples/components/banner/title-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const TitleSuccessBanner = () => {\n  return (\n    <Banner messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography variant=\"body-2-bold\">Success title</Typography>\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Success banner with title"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/link-success-banner",
            "github": "apps/workshop/src/examples/components/banner/link-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Link, Typography } from '@visa/nova-react';\n\nexport const LinkSuccessBanner = () => {\n  return (\n    <Banner messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Link href=\"./banner\">Destination label</Link>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Success banner with link"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/button-success-banner",
            "github": "apps/workshop/src/examples/components/banner/button-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Button, Typography } from '@visa/nova-react';\n\nexport const ButtonSuccessBanner = () => {\n  return (\n    <Banner messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Success banner with button"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Success banners",
          "url": {
            "iframe": "components/banner/persistent-success-banner",
            "github": "apps/workshop/src/examples/components/banner/persistent-success-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Banner, BannerContent, Typography } from '@visa/nova-react';\n\nexport const PersistentSuccessBanner = () => {\n  return (\n    <Banner messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n    </Banner>\n  );\n};\n"
          },
          "name": "Success banner without close icon button"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/empty-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/empty-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Banner } from '@visa/nova-react';\n\nexport const EmptyWarningBanner = () => {\n  return <Banner messageType=\"warning\"></Banner>;\n};\n"
          },
          "name": "Empty warning banner"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/default-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/default-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const DefaultWarningBanner = () => {\n  return (\n    <Banner messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Default warning banner"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/title-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/title-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const TitleWarningBanner = () => {\n  return (\n    <Banner messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography variant=\"body-2-bold\">Warning title</Typography>\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Warning banner with title"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/link-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/link-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Link, Typography } from '@visa/nova-react';\n\nexport const LinkWarningBanner = () => {\n  return (\n    <Banner messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Link href=\"./banner\">Destination label</Link>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Warning banner with link"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/button-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/button-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Button, Typography } from '@visa/nova-react';\n\nexport const ButtonWarningBanner = () => {\n  return (\n    <Banner messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Warning banner with button"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Warning banners",
          "url": {
            "iframe": "components/banner/persistent-warning-banner",
            "github": "apps/workshop/src/examples/components/banner/persistent-warning-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Banner, BannerContent, Typography } from '@visa/nova-react';\n\nexport const PersistentWarningBanner = () => {\n  return (\n    <Banner messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n    </Banner>\n  );\n};\n"
          },
          "name": "Warning banner without close icon button"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/empty-error-banner",
            "github": "apps/workshop/src/examples/components/banner/empty-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Banner } from '@visa/nova-react';\n\nexport const EmptyErrorBanner = () => {\n  return <Banner messageType=\"error\"></Banner>;\n};\n"
          },
          "name": "Empty error banner"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/default-error-banner",
            "github": "apps/workshop/src/examples/components/banner/default-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const DefaultErrorBanner = () => {\n  return (\n    <Banner messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Default error banner"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/title-error-banner",
            "github": "apps/workshop/src/examples/components/banner/title-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Typography } from '@visa/nova-react';\n\nexport const TitleErrorBanner = () => {\n  return (\n    <Banner messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography variant=\"body-2-bold\">Error title</Typography>\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Error banner with title"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/link-error-banner",
            "github": "apps/workshop/src/examples/components/banner/link-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Link, Typography } from '@visa/nova-react';\n\nexport const LinkErrorBanner = () => {\n  return (\n    <Banner messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Link href=\"./banner\">Destination label</Link>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Error banner with link"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/button-error-banner",
            "github": "apps/workshop/src/examples/components/banner/button-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Banner, BannerCloseButton, BannerContent, Button, Typography } from '@visa/nova-react';\n\nexport const ButtonErrorBanner = () => {\n  return (\n    <Banner messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography className=\"v-mb-8\">This is required text that describes the banner in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </BannerContent>\n      <BannerCloseButton>\n        <VisaCloseTiny />\n      </BannerCloseButton>\n    </Banner>\n  );\n};\n"
          },
          "name": "Error banner with button"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Error banners",
          "url": {
            "iframe": "components/banner/persistent-error-banner",
            "github": "apps/workshop/src/examples/components/banner/persistent-error-banner.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Banner, BannerContent, Typography } from '@visa/nova-react';\n\nexport const PersistentErrorBanner = () => {\n  return (\n    <Banner messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <BannerContent className=\"v-pl-2 v-pb-2\">\n        <Typography>This is required text that describes the banner in more detail.</Typography>\n      </BannerContent>\n    </Banner>\n  );\n};\n"
          },
          "name": "Error banner without close icon button"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Custom banners",
          "url": {
            "iframe": "components/banner/reusable",
            "github": "apps/workshop/src/examples/components/banner/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Banner,\n  BannerCloseButton,\n  BannerContent,\n  type BannerProperties,\n  Button,\n  Link,\n  type MessageType,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type ReactNode, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Nova Banner Component Props\nexport type NovaBannerProps = BannerProperties & {\n  buttonLabel?: string;\n  description?: string;\n  dismissible?: boolean;\n  href?: string;\n  icon?: ReactNode;\n  linkLabel?: string;\n  onButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n  onClose?: () => void;\n  showIcon?: boolean;\n  title?: string;\n  titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n};\n\n// Main Nova Banner Component\nexport const NovaBanner = ({\n  buttonLabel,\n  children,\n  description,\n  dismissible = false,\n  href,\n  icon,\n  linkLabel,\n  messageType,\n  onButtonClick,\n  onClose,\n  showIcon = false,\n  title,\n  titleTag = 'h4',\n  ...remainingProps\n}: NovaBannerProps) => {\n  return (\n    <Banner messageType={messageType} {...remainingProps}>\n      {showIcon && <MessageIcon messageType={messageType as Parameters<typeof MessageIcon>[0]['messageType']} />}\n      {icon}\n      <UtilityFragment vPaddingBottom={2} vPaddingLeft={2}>\n        <BannerContent>\n          <Typography variant=\"body-2-bold\" tag={titleTag}>\n            {title}\n          </Typography>\n          {description && <Typography>{description}</Typography>}\n          {buttonLabel && (\n            <UtilityFragment vMarginRight={linkLabel ? 8 : 0} vMarginTop={8}>\n              <Button colorScheme=\"secondary\" onClick={onButtonClick}>\n                {buttonLabel}\n              </Button>\n            </UtilityFragment>\n          )}\n          {linkLabel && <Link href={href}>{linkLabel}</Link>}\n          {children}\n        </BannerContent>\n      </UtilityFragment>\n\n      {dismissible && (\n        <BannerCloseButton aria-label=\"Close\" onClick={onClose}>\n          <VisaCloseTiny />\n        </BannerCloseButton>\n      )}\n    </Banner>\n  );\n};\n\n// export default NovaBanner;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  buttonLabel: string;\n  description: string;\n  dismissible: boolean;\n  href: string;\n  linkLabel: string;\n  messageType: MessageType;\n  showIcon: boolean;\n  title: string;\n  titleTag: NovaBannerProps['titleTag'];\n}\n\n// Demo Component\nexport const NovaBannerDemo = () => {\n  const messageTypes: { label: string; value: MessageType | undefined }[] = [\n    { label: 'Success', value: 'success' },\n    { label: 'Information', value: undefined },\n    { label: 'Warning', value: 'warning' },\n    { label: 'Error', value: 'error' },\n    { label: 'Subtle', value: 'subtle' },\n  ];\n\n  const titleTags: { label: string; value: NovaBannerProps['titleTag'] }[] = [\n    { label: '1', value: 'h1' },\n    { label: '2', value: 'h2' },\n    { label: '3', value: 'h3' },\n    { label: '4', value: 'h4' },\n    { label: '5', value: 'h5' },\n    { label: '6', value: 'h6' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    buttonLabel: '',\n    description: 'This is required text that describes the banner in more detail.',\n    dismissible: true,\n    href: 'www.visa.com',\n    linkLabel: '',\n    messageType: 'success',\n    showIcon: true,\n    title: 'Success title',\n    titleTag: 'h4',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  const handleClose = () => {\n    console.log('Section message closed');\n  };\n\n  const handleClick = () => {\n    console.log('Section message button clicked');\n  };\n\n  return (\n    <>\n      <NovaBanner\n        buttonLabel={customizations.buttonLabel || ''}\n        description={customizations.description || ''}\n        dismissible={customizations.dismissible}\n        href={customizations.href || ''}\n        linkLabel={customizations.linkLabel || ''}\n        messageType={customizations.messageType}\n        onButtonClick={handleClick}\n        onClose={handleClose}\n        showIcon={customizations.showIcon}\n        title={customizations.title || ''}\n        titleTag={customizations.titleTag}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Button label\"\n                onChange={e => handleInputChange('buttonLabel', e.target.value)}\n                value={formValues.buttonLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Href\"\n                onChange={e => handleInputChange('href', e.target.value)}\n                value={formValues.href}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Link label\"\n                onChange={e => handleInputChange('linkLabel', e.target.value)}\n                value={formValues.linkLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Title\"\n                onChange={e => handleInputChange('title', e.target.value)}\n                value={formValues.title}\n              />\n\n              <NovaSelect\n                label=\"Message type\"\n                onChange={e => handleInputChange('messageType', e.target.value as MessageType)}\n                options={messageTypes}\n                value={formValues.messageType}\n              />\n\n              <NovaSelect\n                label=\"Title level\"\n                onChange={e => handleInputChange('titleTag', e.target.value)}\n                value={formValues.titleTag}\n                options={titleTags}\n              />\n\n              <NovaCheckbox\n                checked={formValues.dismissible}\n                label=\"Dismissible\"\n                onChange={e => handleInputChange('dismissible', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Show icon\"\n                checked={formValues.showIcon}\n                onChange={e => handleInputChange('showIcon', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </>\n  );\n};\nexport default NovaBannerDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable banner"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Banner",
          "selector": "<Banner />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Messages indicating the global status of an application or website."
        },
        {
          "order": 2,
          "name": "BannerCloseButton",
          "selector": "<BannerCloseButton />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Close button used in upper corner of banner."
        },
        {
          "order": 3,
          "name": "Messagecontent",
          "selector": "<MessageContent />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for message content elements."
        }
      ],
      "properties": [
        {
          "name": "messageType",
          "section": "Banner",
          "data": {
            "name": "messageType",
            "type": "\"subtle\" , \"warning\" , \"error\" , \"information\" , \"success\"",
            "default": "",
            "required": "false",
            "description": "Message Type"
          }
        },
        {
          "name": "tag",
          "section": "Banner",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "BannerCloseButton",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "BannerCloseButton",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "children",
          "section": "BannerCloseButton",
          "data": {
            "name": "children",
            "type": "ReactNode",
            "default": "",
            "required": "false",
            "description": "@required"
          }
        },
        {
          "name": "colorScheme",
          "section": "BannerCloseButton",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "BannerCloseButton",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "BannerCloseButton",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "BannerCloseButton",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "BannerCloseButton",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "BannerCloseButton",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "BannerCloseButton",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "BannerCloseButton",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "tag",
          "section": "Messagecontent",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "breadcrumbs",
      "version": "0.0.1",
      "description": "Supplemental navigation indicating the user's location in a site or app.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Examples",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/breadcrumbs/default-breadcrumbs",
            "github": "apps/workshop/src/examples/components/breadcrumbs/default-breadcrumbs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Breadcrumbs, Link } from '@visa/nova-react';\n\nexport const DefaultBreadcrumbs = () => {\n  return (\n    <Breadcrumbs aria-label=\"Default breadcrumbs\">\n      <ol>\n        <li>\n          <Link href=\"./\">L1 label</Link>\n        </li>\n        <li>\n          <Link href=\"./\">L2 label</Link>\n        </li>\n        <li>\n          <Link href=\"./\">L3 label</Link>\n        </li>\n        <li>\n          <span aria-current=\"page\">L4 label</span>\n        </li>\n      </ol>\n    </Breadcrumbs>\n  );\n};\n"
          },
          "name": "Breadcrumbs with default separator"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/breadcrumbs/custom-separator-breadcrumbs",
            "github": "apps/workshop/src/examples/components/breadcrumbs/custom-separator-breadcrumbs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Breadcrumbs, Link } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const CustomSeparatorBreadcrumbs = () => {\n  return (\n    <Breadcrumbs\n      aria-label=\"Custom separator breadcrumbs\"\n      style={{ '--v-breadcrumbs-pseudo-separator': \"'+'\" } as CSSProperties}\n    >\n      <ol>\n        <li>\n          <Link href=\"./\">L1 label</Link>\n        </li>\n        <li>\n          <Link href=\"./\">L2 label</Link>\n        </li>\n        <li>\n          <Link href=\"./\">L3 label</Link>\n        </li>\n        <li>\n          <span aria-current=\"page\">L4 label</span>\n        </li>\n      </ol>\n    </Breadcrumbs>\n  );\n};\n"
          },
          "name": "Breadcrumbs with custom separator"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/breadcrumbs/inline-separator-breadcrumbs",
            "github": "apps/workshop/src/examples/components/breadcrumbs/inline-separator-breadcrumbs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Breadcrumbs, Link } from '@visa/nova-react';\n\nexport const InlineSeparatorBreadcrumbs = () => {\n  return (\n    <Breadcrumbs aria-label=\"Inline separator breadcrumbs\" customSeparator>\n      <ol>\n        <li>\n          <Link href=\"./\">L1 label</Link> <span aria-hidden=\"true\">|</span>\n        </li>\n        <li>\n          <Link href=\"./\">L2 label</Link> <span aria-hidden=\"true\">|</span>\n        </li>\n        <li>\n          <Link href=\"./\">L3 label</Link> <span aria-hidden=\"true\">|</span>\n        </li>\n        <li>\n          <span aria-current=\"page\">L4 label</span>\n        </li>\n      </ol>\n    </Breadcrumbs>\n  );\n};\n"
          },
          "name": "Breadcrumbs with inline separator"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/breadcrumbs/inline-svg-separator-breadcrumbs",
            "github": "apps/workshop/src/examples/components/breadcrumbs/inline-svg-separator-breadcrumbs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Breadcrumbs, Link } from '@visa/nova-react';\n\nexport const InlineSVGSeparatorBreadcrumbs = () => {\n  return (\n    <Breadcrumbs aria-label=\"Custom svg separator breadcrumbs\" customSeparator>\n      <ol>\n        <li>\n          <Link href=\"./\">L1 label</Link> <VisaChevronRightTiny rtl />\n        </li>\n        <li>\n          <Link href=\"./\">L2 label</Link> <VisaChevronRightTiny rtl />\n        </li>\n        <li>\n          <Link href=\"./\">L3 label</Link> <VisaChevronRightTiny rtl />\n        </li>\n        <li>\n          <span aria-current=\"page\">L4 label</span>\n        </li>\n      </ol>\n    </Breadcrumbs>\n  );\n};\n"
          },
          "name": "Breadcrumbs with SVG separator"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Breadcrumbs",
          "selector": "<Breadcrumbs />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Supplemental navigation indicating the user's location in a site or app."
        }
      ],
      "properties": [
        {
          "name": "customSeparator",
          "section": "Breadcrumbs",
          "data": {
            "name": "customSeparator",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Use Custom Separator"
          }
        },
        {
          "name": "tag",
          "section": "Breadcrumbs",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "nav",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "button",
      "version": "0.0.1",
      "description": "Interactive elements enabling users to take actions within an interface.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Primary text buttons",
          "description": "",
          "order": 1
        },
        {
          "name": "Secondary text buttons",
          "description": "",
          "order": 2
        },
        {
          "name": "Tertiary text buttons",
          "description": "",
          "order": 3
        },
        {
          "name": "Destructive text buttons",
          "description": "",
          "order": 4
        },
        {
          "name": "Primary icon buttons",
          "description": "",
          "order": 5
        },
        {
          "name": "Secondary icon buttons",
          "description": "",
          "order": 6
        },
        {
          "name": "UI icon buttons",
          "description": "",
          "order": 7
        },
        {
          "name": "Stacked icon buttons",
          "description": "",
          "order": 8
        },
        {
          "name": "Button coded as a link",
          "description": "",
          "order": 9
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/default-button",
            "github": "apps/workshop/src/examples/components/button/default-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const DefaultButton = () => {\n  return <Button>Primary action</Button>;\n};\n"
          },
          "name": "Default primary text button"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/alternate-button",
            "github": "apps/workshop/src/examples/components/button/alternate-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const AlternateButton = () => {\n  return <Button alternate>Primary action</Button>;\n};\n"
          },
          "name": "Alternate primary text button"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/with-leading-icon-button",
            "github": "apps/workshop/src/examples/components/button/with-leading-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithLeadingIconButton = () => {\n  return (\n    <Button iconTwoColor>\n      <VisaFileUploadTiny />\n      Primary action\n    </Button>\n  );\n};\n"
          },
          "name": "Primary text button with leading icon"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/with-trailing-icon-button",
            "github": "apps/workshop/src/examples/components/button/with-trailing-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithTrailingIconButton = () => {\n  return (\n    <Button iconTwoColor>\n      Primary action\n      <VisaFileUploadTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Primary text button with trailing icon"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/disabled-button",
            "github": "apps/workshop/src/examples/components/button/disabled-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DisabledButton = () => {\n  return (\n    <Button disabled>\n      <VisaFileUploadTiny />\n      Primary action\n    </Button>\n  );\n};\n"
          },
          "name": "Disabled primary text button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/small-button",
            "github": "apps/workshop/src/examples/components/button/small-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SmallButton = () => {\n  return (\n    <Button buttonSize=\"small\" iconTwoColor>\n      <VisaFileUploadTiny />\n      Primary action\n    </Button>\n  );\n};\n"
          },
          "name": "Small primary text button"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Primary text buttons",
          "url": {
            "iframe": "components/button/large-button",
            "github": "apps/workshop/src/examples/components/button/large-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeButton = () => {\n  return (\n    <Button buttonSize=\"large\" iconTwoColor>\n      <VisaFileUploadTiny />\n      Primary action\n    </Button>\n  );\n};\n"
          },
          "name": "Large primary text button"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/secondary-button",
            "github": "apps/workshop/src/examples/components/button/secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const SecondaryButton = () => {\n  return <Button colorScheme=\"secondary\">Secondary action</Button>;\n};\n"
          },
          "name": "Default secondary text button"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/alternate-secondary-button",
            "github": "apps/workshop/src/examples/components/button/alternate-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const AlternateSecondaryButton = () => {\n  return (\n    <Button alternate colorScheme=\"secondary\">\n      Secondary action\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate secondary text button"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/with-leading-icon-secondary-button",
            "github": "apps/workshop/src/examples/components/button/with-leading-icon-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSaveTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithLeadingIconSecondaryButton = () => {\n  return (\n    <Button colorScheme=\"secondary\">\n      <VisaSaveTiny />\n      Secondary action\n    </Button>\n  );\n};\n"
          },
          "name": "Secondary text button with leading icon"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/with-trailing-icon-secondary-button",
            "github": "apps/workshop/src/examples/components/button/with-trailing-icon-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSaveTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithTrailingIconSecondaryButton = () => {\n  return (\n    <Button colorScheme=\"secondary\">\n      Secondary action\n      <VisaSaveTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Secondary text button with trailing icon"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/disabled-secondary-button",
            "github": "apps/workshop/src/examples/components/button/disabled-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSaveTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DisabledSecondaryButton = () => {\n  return (\n    <Button colorScheme=\"secondary\" disabled>\n      <VisaSaveTiny />\n      Secondary action\n    </Button>\n  );\n};\n"
          },
          "name": "Disabled secondary text button"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/small-secondary-button",
            "github": "apps/workshop/src/examples/components/button/small-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSaveTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SmallSecondaryButton = () => {\n  return (\n    <Button buttonSize=\"small\" colorScheme=\"secondary\">\n      <VisaSaveTiny />\n      Secondary action\n    </Button>\n  );\n};\n"
          },
          "name": "Small secondary text button"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary text buttons",
          "url": {
            "iframe": "components/button/large-secondary-button",
            "github": "apps/workshop/src/examples/components/button/large-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSaveTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeSecondaryButton = () => {\n  return (\n    <Button buttonSize=\"large\" colorScheme=\"secondary\">\n      <VisaSaveTiny />\n      Secondary action\n    </Button>\n  );\n};\n"
          },
          "name": "Large secondary text button"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/tertiary-button",
            "github": "apps/workshop/src/examples/components/button/tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const TertiaryButton = () => {\n  return <Button colorScheme=\"tertiary\">Tertiary action</Button>;\n};\n"
          },
          "name": "Default tertiary text button"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/alternate-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/alternate-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button } from '@visa/nova-react';\n\nexport const AlternateTertiaryButton = () => {\n  return (\n    <Button alternate colorScheme=\"tertiary\">\n      Tertiary action\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate tertiary text button"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/with-leading-icon-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/with-leading-icon-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithLeadingIconTertiaryButton = () => {\n  return (\n    <Button colorScheme=\"tertiary\">\n      <VisaHistoryTiny />\n      Tertiary action\n    </Button>\n  );\n};\n"
          },
          "name": "Tertiary text button with leading icon"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/with-trailing-icon-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/with-trailing-icon-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const WithTrailingIconTertiaryButton = () => {\n  return (\n    <Button colorScheme=\"tertiary\">\n      Tertiary action\n      <VisaHistoryTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Tertiary text button with trailing icon"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/disabled-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/disabled-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DisabledTertiaryButton = () => {\n  return (\n    <Button colorScheme=\"tertiary\" disabled>\n      <VisaHistoryTiny />\n      Tertiary action\n    </Button>\n  );\n};\n"
          },
          "name": "Disabled tertiary text button"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/small-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/small-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SmallTertiaryButton = () => {\n  return (\n    <Button buttonSize=\"small\" colorScheme=\"tertiary\">\n      <VisaHistoryTiny />\n      Tertiary action\n    </Button>\n  );\n};\n"
          },
          "name": "Small tertiary text button"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Tertiary text buttons",
          "url": {
            "iframe": "components/button/large-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/large-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHistoryTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeTertiaryButton = () => {\n  return (\n    <Button buttonSize=\"large\" colorScheme=\"tertiary\">\n      <VisaHistoryTiny />\n      Tertiary action\n    </Button>\n  );\n};\n"
          },
          "name": "Large tertiary text button"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Destructive text buttons",
          "url": {
            "iframe": "components/button/destructive-button",
            "github": "apps/workshop/src/examples/components/button/destructive-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDeleteTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DestructiveButton = () => {\n  return (\n    <Button destructive>\n      <VisaDeleteTiny />\n      Destructive action\n    </Button>\n  );\n};\n"
          },
          "name": "Primary destructive text button"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Destructive text buttons",
          "url": {
            "iframe": "components/button/destructive-secondary-button",
            "github": "apps/workshop/src/examples/components/button/destructive-secondary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDeleteTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DestructiveSecondaryButton = () => {\n  return (\n    <Button destructive colorScheme=\"secondary\">\n      <VisaDeleteTiny />\n      Destructive action\n    </Button>\n  );\n};\n"
          },
          "name": "Secondary destructive text button"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Destructive text buttons",
          "url": {
            "iframe": "components/button/destructive-tertiary-button",
            "github": "apps/workshop/src/examples/components/button/destructive-tertiary-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDeleteTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const DestructiveTertiaryButton = () => {\n  return (\n    <Button colorScheme=\"tertiary\" destructive>\n      <VisaDeleteTiny />\n      Destructive action\n    </Button>\n  );\n};\n"
          },
          "name": "Tertiary destructive text button"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/icon-button",
            "github": "apps/workshop/src/examples/components/button/icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const IconButton = () => {\n  return (\n    <Button aria-label=\"action\" iconButton>\n      <VisaAddTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Default primary icon button"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/icon-alternate-button",
            "github": "apps/workshop/src/examples/components/button/icon-alternate-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const IconAlternateButton = () => {\n  return (\n    <Button alternate aria-label=\"action\" iconButton>\n      <VisaAddTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate primary icon button"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/with-label-icon-button",
            "github": "apps/workshop/src/examples/components/button/with-label-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddTiny } from '@visa/nova-icons-react';\nimport { Button, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'icon-button';\n\nexport const WithLabelIconButton = () => {\n  return (\n    <Utility vFlex vFlexRow>\n      <Utility vAlignItems=\"center\" vFlex vFlexCol vGap={2}>\n        <Button aria-labelledby={`${id}-label`} iconButton>\n          <VisaAddTiny />\n        </Button>\n        <Typography id={`${id}-label`} tag=\"span\" variant=\"label-small\">\n          Action\n        </Typography>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Primary icon button with label"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/disabled-icon-button",
            "github": "apps/workshop/src/examples/components/button/disabled-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddTiny } from '@visa/nova-icons-react';\nimport { Button, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-icon-button';\n\nexport const DisabledIconButton = () => {\n  return (\n    <Utility vFlex vFlexRow>\n      <Utility vAlignItems=\"center\" vFlex vFlexCol vGap={2}>\n        <Button aria-labelledby={`${id}-label`} disabled iconButton>\n          <VisaAddTiny />\n        </Button>\n        <Typography\n          id={`${id}-label`}\n          style={{ color: 'var(--palette-default-disabled)' }}\n          tag=\"span\"\n          variant=\"label-small\"\n        >\n          Action\n        </Typography>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled primary icon button"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/small-icon-button",
            "github": "apps/workshop/src/examples/components/button/small-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SmallIconButton = () => {\n  return (\n    <Button aria-label=\"action\" buttonSize=\"small\" iconButton iconTwoColor>\n      <VisaAddTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Small primary icon button"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Primary icon buttons",
          "url": {
            "iframe": "components/button/large-icon-button",
            "github": "apps/workshop/src/examples/components/button/large-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAddLow } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeIconButton = () => {\n  return (\n    <Button aria-label=\"action\" buttonSize=\"large\" iconButton iconTwoColor>\n      <VisaAddLow />\n    </Button>\n  );\n};\n"
          },
          "name": "Large primary icon button"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary icon buttons",
          "url": {
            "iframe": "components/button/secondary-icon-button",
            "github": "apps/workshop/src/examples/components/button/secondary-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaConnectTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SecondaryIconButton = () => {\n  return (\n    <Button aria-label=\"action\" colorScheme=\"secondary\" iconButton>\n      <VisaConnectTiny rtl />\n    </Button>\n  );\n};\n"
          },
          "name": "Default secondary icon button"
        },
        {
          "description": "",
          "order": 32,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary icon buttons",
          "url": {
            "iframe": "components/button/secondary-alternate-icon-button",
            "github": "apps/workshop/src/examples/components/button/secondary-alternate-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaConnectTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SecondaryAlternateIconButton = () => {\n  return (\n    <Button alternate aria-label=\"action\" colorScheme=\"secondary\" iconButton>\n      <VisaConnectTiny rtl />\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate secondary icon button"
        },
        {
          "description": "",
          "order": 33,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary icon buttons",
          "url": {
            "iframe": "components/button/with-label-secondary-icon-button",
            "github": "apps/workshop/src/examples/components/button/with-label-secondary-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaConnectTiny } from '@visa/nova-icons-react';\nimport { Button, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'secondary-icon-button';\n\nexport const WithLabelSecondaryIconButton = () => {\n  return (\n    <Utility vFlex vFlexRow>\n      <Utility vAlignItems=\"center\" vFlex vFlexCol vGap={2}>\n        <Button aria-labelledby={`${id}-label`} colorScheme=\"secondary\" iconButton>\n          <VisaConnectTiny rtl />\n        </Button>\n        <Typography id={`${id}-label`} tag=\"span\" variant=\"label-small\">\n          Action\n        </Typography>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Secondary icon button with label"
        },
        {
          "description": "",
          "order": 34,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary icon buttons",
          "url": {
            "iframe": "components/button/disabled-secondary-icon-button",
            "github": "apps/workshop/src/examples/components/button/disabled-secondary-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaConnectTiny } from '@visa/nova-icons-react';\nimport { Button, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-secondary-icon-button';\n\nexport const DisabledSecondaryIconButton = () => {\n  return (\n    <Utility vFlex vFlexRow>\n      <Utility vAlignItems=\"center\" vFlex vFlexCol>\n        <Button aria-labelledby={`${id}-label`} colorScheme=\"secondary\" disabled iconButton>\n          <VisaConnectTiny rtl />\n        </Button>\n        <Typography\n          id={`${id}-label`}\n          style={{ color: 'var(--palette-default-disabled)' }}\n          tag=\"span\"\n          variant=\"label-small\"\n        >\n          Action\n        </Typography>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled secondary icon button"
        },
        {
          "description": "",
          "order": 35,
          "libraryId": null,
          "componentId": null,
          "section": "Secondary icon buttons",
          "url": {
            "iframe": "components/button/large-secondary-icon-button",
            "github": "apps/workshop/src/examples/components/button/large-secondary-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaConnectLow } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeSecondaryIconButton = () => {\n  return (\n    <Button aria-label=\"action\" buttonSize=\"large\" colorScheme=\"secondary\" iconButton>\n      <VisaConnectLow rtl />\n    </Button>\n  );\n};\n"
          },
          "name": "Large secondary icon button"
        },
        {
          "description": "",
          "order": 36,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/small-ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/small-ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SmallUiIconButton = () => {\n  return (\n    <Button aria-label=\"action\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n      <VisaNotificationsTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Small UI icon button"
        },
        {
          "description": "",
          "order": 37,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const UiIconButton = () => {\n  return (\n    <Button aria-label=\"action\" colorScheme=\"tertiary\" iconButton>\n      <VisaNotificationsTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Medium UI icon button"
        },
        {
          "description": "",
          "order": 38,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/large-ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/large-ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsLow } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const LargeUiIconButton = () => {\n  return (\n    <Button aria-label=\"action\" buttonSize=\"large\" colorScheme=\"tertiary\" iconButton>\n      <VisaNotificationsLow />\n    </Button>\n  );\n};\n"
          },
          "name": "Large UI icon button"
        },
        {
          "description": "",
          "order": 39,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/subtle-ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/subtle-ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const SubtleUiIconButton = () => {\n  return (\n    <Button aria-label=\"action\" colorScheme=\"tertiary\" iconButton subtle>\n      <VisaNotificationsTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Subtle UI icon button"
        },
        {
          "description": "",
          "order": 40,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/with-badge-number-ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/with-badge-number-ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsTiny } from '@visa/nova-icons-react';\nimport { Badge, Button } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'with-badge-number-ui-icon-button';\n\nexport const WithBadgeNumberUiIconButton = () => {\n  return (\n    <Button aria-describedby={`${id}-badge`} buttonSize=\"large\" colorScheme=\"tertiary\" iconButton>\n      <VisaNotificationsTiny />\n      <Badge aria-label=\"9 unread notifications\" badgeVariant=\"number\" id={`${id}-badge`} tag=\"sup\">\n        9\n      </Badge>\n    </Button>\n  );\n};\n"
          },
          "name": "UI icon button with badge"
        },
        {
          "description": "",
          "order": 41,
          "libraryId": null,
          "componentId": null,
          "section": "UI icon buttons",
          "url": {
            "iframe": "components/button/alternate-ui-icon-button",
            "github": "apps/workshop/src/examples/components/button/alternate-ui-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaNotificationsTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const AlternateUiIconButton = () => {\n  return (\n    <Button alternate aria-label=\"action\" colorScheme=\"tertiary\" iconButton>\n      <VisaNotificationsTiny />\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate UI icon button"
        },
        {
          "description": "",
          "order": 42,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked icon buttons",
          "url": {
            "iframe": "components/button/stacked-icon-button",
            "github": "apps/workshop/src/examples/components/button/stacked-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaGlossaryLow } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const StackedIconButton = () => {\n  return (\n    <Button colorScheme=\"tertiary\" stacked>\n      <VisaGlossaryLow />\n      Action\n    </Button>\n  );\n};\n"
          },
          "name": "Default stacked icon button"
        },
        {
          "description": "",
          "order": 43,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked icon buttons",
          "url": {
            "iframe": "components/button/alternate-stacked-icon-button",
            "github": "apps/workshop/src/examples/components/button/alternate-stacked-icon-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaGlossaryLow } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const AlternateStackedIconButton = () => {\n  return (\n    <Button alternate colorScheme=\"tertiary\" stacked>\n      <VisaGlossaryLow />\n      Action\n    </Button>\n  );\n};\n"
          },
          "name": "Alternate stacked icon button"
        },
        {
          "description": "",
          "order": 44,
          "libraryId": null,
          "componentId": null,
          "section": "Button coded as a link",
          "url": {
            "iframe": "components/button/coded-as-link-button",
            "github": "apps/workshop/src/examples/components/button/coded-as-link-button.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Button } from '@visa/nova-react';\n\nexport const CodedAsLinkButton = () => {\n  return (\n    <Button\n      element={\n        <a href=\"./button\">\n          Primary action\n          <VisaChevronRightTiny rtl />\n        </a>\n      }\n    />\n  );\n};\n"
          },
          "name": "Button coded as a link"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Button",
          "selector": "<Button />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive elements enabling users to take actions within an interface."
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Button",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "Button",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "colorScheme",
          "section": "Button",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "Button",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "Button",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "Button",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "Button",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "Button",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "Button",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "Button",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "button",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        }
      ]
    },
    {
      "name": "checkbox",
      "version": "0.0.1",
      "description": "Interactive element enabling users to select one or more independent options from a group.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default checkboxes",
          "description": "",
          "order": 1
        },
        {
          "name": "Checkbox groups",
          "description": "",
          "order": 2
        },
        {
          "name": "Checkbox panels",
          "description": "",
          "order": 3
        },
        {
          "name": "Checkbox panels group",
          "description": "",
          "order": 4
        },
        {
          "name": "Custom checkboxes",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/default-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/default-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-default';\n\nexport const DefaultCheckbox = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Checkbox id={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Checkbox with label"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/standalone-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/standalone-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Utility } from '@visa/nova-react';\n\nexport const StandaloneCheckbox = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Checkbox aria-label=\"label\" />\n    </Utility>\n  );\n};\n"
          },
          "name": "Checkbox without visible label"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/inline-message-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/inline-message-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'inline-message-checkbox';\n\nexport const InlineMessageCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <Utility vFlex vGap={2}>\n        <Checkbox id={id} />\n        <Utility vFlex vFlexCol vGap={2} vMarginVertical={10}>\n          <Label htmlFor={id}>Label</Label>\n          <InputMessage id={`${id}-message`}>\n            This is optional text that describes the label in more detail.\n          </InputMessage>\n        </Utility>\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Checkbox with description"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/checked-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/checked-checkbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checked-checkbox';\n\nexport const CheckedCheckbox = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Checkbox defaultChecked id={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Checked checkbox"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/validation-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/validation-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useRef, useState, type ChangeEvent } from 'react';\nimport { Button, Checkbox, InputMessage, Label, Utility, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'validation-checkbox';\n\nexport const ValidationCheckbox = () => {\n  const checkboxRef = useRef<HTMLInputElement>(null);\n  const [checked, setChecked] = useState(false);\n  const [invalid, setInvalid] = useState(false);\n\n  const onCheckboxChange = (event: ChangeEvent<HTMLInputElement>) => {\n    setChecked(event.target.checked);\n  };\n\n  const onSubmit = () => {\n    if (checked) return setInvalid(false);\n    setInvalid(true);\n    checkboxRef.current?.focus();\n  };\n\n  return (\n    <>\n      <Utility tag=\"fieldset\" vFlex vFlexCol>\n        <Utility vAlignItems=\"center\" vFlex vGap={2}>\n          <Checkbox\n            aria-describedby={`${id}-message`}\n            aria-invalid={invalid}\n            aria-required={true}\n            checked={checked}\n            id={id}\n            onChange={onCheckboxChange}\n            ref={checkboxRef}\n            value=\"1\"\n          />\n          <Label htmlFor={id}>Label</Label>\n        </Utility>\n        {invalid && (\n          <UtilityFragment vMarginTop={4}>\n            <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\" variant=\"body-3\">\n              <VisaErrorTiny />\n              This is required text that describes the error in more detail.\n            </InputMessage>\n          </UtilityFragment>\n        )}\n      </Utility>\n      <UtilityFragment vMarginTop={12}>\n        <Button onClick={onSubmit}>Submit</Button>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Checkbox with error"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/disabled-unchecked-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/disabled-unchecked-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-disabled';\n\nexport const DisabledUncheckedCheckbox = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Checkbox disabled id={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled checkbox"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default checkboxes",
          "url": {
            "iframe": "components/checkbox/disabled-checked-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/disabled-checked-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-disabled-checked';\n\nexport const DisabledCheckedCheckbox = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Checkbox id={id} disabled checked />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled checked checkbox"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox groups",
          "url": {
            "iframe": "components/checkbox/group-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/group-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-group';\n\nconst checkboxes = ['Label 1', 'Label 2', 'Label 3', 'Label 4'];\n\nexport const GroupCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-legend`}>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Group label\n      </Label>\n      <Utility tag=\"ul\" vFlex vFlexCol>\n        {checkboxes.map((checkbox, index) => (\n          <Utility key={`${id}-option-${index}`} tag=\"li\" vAlignItems=\"center\" vFlex vGap={2}>\n            <Checkbox id={`${id}-option-${index}`} />\n            <Label htmlFor={`${id}-option-${index}`}>{checkbox}</Label>\n          </Utility>\n        ))}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Checkbox group"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox groups",
          "url": {
            "iframe": "components/checkbox/group-with-validation-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/group-with-validation-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, Checkbox, InputMessage, Label, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useRef, useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'group-with-validation-checkbox';\n\ntype CheckboxStats = {\n  checked: boolean;\n  label: string;\n  required: boolean;\n  value: string;\n};\n\nconst defaultCheckboxStats: CheckboxStats[] = [\n  {\n    checked: false,\n    label: 'Label 1',\n    required: true,\n    value: 'label-1',\n  },\n  {\n    checked: true,\n    label: 'Label 2',\n    required: true,\n    value: 'label-2',\n  },\n  {\n    checked: false,\n    label: 'Label 3',\n    required: true,\n    value: 'label-3',\n  },\n  {\n    checked: false,\n    label: 'Label 4',\n    required: true,\n    value: 'label-4',\n  },\n];\n\nexport const GroupWithValidationCheckbox = () => {\n  const checkboxRefs = useRef<(HTMLInputElement | null)[]>([]);\n  const [checkboxStats, setCheckboxStats] = useState(defaultCheckboxStats);\n  const [invalid, setInvalid] = useState(false);\n\n  const onCheckboxChange = (event: FormEvent<HTMLInputElement>, index: number) => {\n    const { checked } = event.currentTarget;\n    const newCheckboxStats = [...checkboxStats];\n    newCheckboxStats[index].checked = checked;\n    setCheckboxStats(newCheckboxStats);\n  };\n\n  const onSubmit = () => {\n    // Check if any of the checkbox are checked\n    const isInvalid = !checkboxStats.some(checkbox => checkbox.checked);\n    // Set invalid state\n    setInvalid(isInvalid);\n    // If invalid focus on the first checkbox\n    if (isInvalid) checkboxRefs.current[0]?.focus();\n  };\n\n  return (\n    <>\n      <fieldset aria-labelledby={`${id}-legend`}>\n        <Label aria-describedby={`${id}-message`} id={`${id}-legend`} tag=\"legend\">\n          Group label\n        </Label>\n        <Utility tag=\"ul\" vFlex vFlexCol>\n          {checkboxStats.map((checkboxStat, index) => (\n            <Utility key={index} tag=\"li\" vAlignItems=\"center\" vFlex vGap={2}>\n              <Checkbox\n                aria-invalid={invalid}\n                checked={checkboxStat.checked}\n                id={`${id}-option-${index}`}\n                onChange={event => onCheckboxChange(event, index)}\n                ref={ref => {\n                  checkboxRefs.current[index] = ref;\n                }}\n                value={checkboxStat.value}\n              />\n              <Label htmlFor={`${id}-option-${index}`}>{checkboxStat.label}</Label>\n            </Utility>\n          ))}\n        </Utility>\n\n        <UtilityFragment vMarginTop={4}>\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\" variant=\"body-3\">\n            {invalid && (\n              <>\n                <VisaErrorTiny />\n                This is required text that describes the error in more detail.\n              </>\n            )}\n          </InputMessage>\n        </UtilityFragment>\n      </fieldset>\n      <UtilityFragment vMarginTop={12}>\n        <Button onClick={onSubmit}>Submit</Button>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Checkbox group with error"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox groups",
          "url": {
            "iframe": "components/checkbox/indeterminate-group-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/indeterminate-group-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\nimport { forwardRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'indeterminate-group-checkbox';\n\ntype Option = {\n  checked?: boolean;\n  children?: Option[];\n  disabled?: boolean;\n  label: string;\n};\n\n// NOTE: This example only works with one level of nesting. A different data structure and way of state management would be required for deeper nesting.\nconst defaultOptions: Option[] = [\n  {\n    label: 'L1 label 1',\n    children: [\n      {\n        checked: true,\n        label: 'L2 label 1',\n      },\n      {\n        label: 'L2 label 2',\n      },\n      {\n        label: 'L2 label 3',\n      },\n    ],\n  },\n];\n\ntype CheckboxGroupProps = {\n  disabled?: boolean;\n  invalid?: boolean;\n  onCheckboxChange: (checked: boolean, parentIndex: number | undefined, childIndex: number) => void;\n  options: Option[];\n  parentId: string;\n  parentIndex?: number;\n};\n\nconst CheckboxGroup = forwardRef<HTMLInputElement, CheckboxGroupProps>(\n  ({ disabled, invalid, onCheckboxChange, options, parentId, parentIndex }: CheckboxGroupProps, ref) =>\n    options.map((option, index) => {\n      const optionId = `${parentId}-option-${index}`;\n      const someChildrenChecked = option.children?.some(child => child.checked);\n      const someChildrenUnchecked = option.children?.some(child => !child.checked);\n      const indeterminate = someChildrenChecked && someChildrenUnchecked;\n      return (\n        <Utility key={optionId} tag=\"li\" vFlex vFlexCol>\n          <Utility vAlignItems=\"center\" vFlex vGap={2}>\n            <Checkbox\n              aria-invalid={invalid}\n              checked={!indeterminate && (option.checked ?? false)}\n              disabled={option.disabled || disabled}\n              id={optionId}\n              indeterminate={indeterminate}\n              onChange={event => onCheckboxChange(event.currentTarget.checked, parentIndex, index)}\n              ref={index === 0 ? ref : undefined}\n            />\n            <Label htmlFor={optionId}>{option.label}</Label>\n          </Utility>\n          {option?.children && (\n            <Utility vFlex vFlexCol vMarginLeft={16} tag=\"ul\">\n              <CheckboxGroup\n                disabled={option.disabled || disabled}\n                invalid={invalid}\n                onCheckboxChange={onCheckboxChange}\n                options={option.children}\n                parentId={optionId}\n                parentIndex={(parentIndex || 0) + index}\n              />\n            </Utility>\n          )}\n        </Utility>\n      );\n    })\n);\n\nCheckboxGroup.displayName = 'CheckboxGroup';\n\nexport const IndeterminateGroupCheckbox = () => {\n  const [options, setOptions] = useState(defaultOptions);\n\n  const onCheckboxChange = (checked: boolean, parentIndex: number | undefined, childIndex: number) => {\n    // Initialize our new options array\n    const newOptions = [...options];\n\n    const checkboxGroup = newOptions[parentIndex === undefined ? childIndex : parentIndex];\n    const checkboxChild = checkboxGroup?.children && checkboxGroup?.children[childIndex];\n    // If parentIndex is undefined then it is a parent checkbox change\n    if (parentIndex === undefined) {\n      checkboxGroup.checked = checked;\n      checkboxGroup.children?.forEach(child => {\n        child.checked = checked;\n      });\n    }\n    // If children exist and they're all checked make sure the group is checked\n    if (checkboxChild) {\n      checkboxChild.checked = checked;\n      const allChildrenChecked = checkboxGroup.children?.every(child => child?.checked) || false;\n      checkboxGroup.checked = allChildrenChecked;\n    }\n\n    // Update the state\n    setOptions(newOptions);\n  };\n\n  return (\n    <fieldset aria-labelledby={`${id}-legend`} style={{ '--v-checkbox-group-gap': '8px' } as CSSProperties}>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Group label\n      </Label>\n      <Utility tag=\"ul\" vFlex vFlexCol>\n        <CheckboxGroup onCheckboxChange={onCheckboxChange} options={options} parentId={id} />\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Indeterminate checkbox group"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox groups",
          "url": {
            "iframe": "components/checkbox/error-indeterminate-group-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/error-indeterminate-group-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, Checkbox, InputMessage, Label, Utility } from '@visa/nova-react';\nimport { forwardRef, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-indeterminate-group-checkbox';\n\ntype Option = {\n  checked?: boolean;\n  children?: Option[];\n  disabled?: boolean;\n  label: string;\n};\n\n// NOTE: This example only works with one level of nesting. A different data structure and way of state management would be required for deeper nesting.\nconst defaultOptions: Option[] = [\n  {\n    label: 'L1 label 1',\n    children: [\n      {\n        checked: true,\n        label: 'L2 label 1',\n      },\n      {\n        label: 'L2 label 2',\n      },\n      {\n        label: 'L2 label 3',\n      },\n    ],\n  },\n];\n\ntype CheckboxGroupProps = {\n  disabled?: boolean;\n  invalid?: boolean;\n  onCheckboxChange: (checked: boolean, parentIndex: number | undefined, childIndex: number) => void;\n  options: Option[];\n  parentId: string;\n  parentIndex?: number;\n};\n\nconst CheckboxGroup = forwardRef<HTMLInputElement, CheckboxGroupProps>(\n  ({ disabled, invalid, onCheckboxChange, options, parentId, parentIndex }: CheckboxGroupProps, ref) =>\n    options.map((option, index) => {\n      const optionId = `${parentId}-option-${index}`;\n      const someChildrenChecked = option.children?.some(child => child.checked);\n      const someChildrenUnchecked = option.children?.some(child => !child.checked);\n      const indeterminate = someChildrenChecked && someChildrenUnchecked;\n      return (\n        <Utility key={optionId} tag=\"li\" vFlex vFlexCol>\n          <Utility vAlignItems=\"center\" vFlex vGap={2}>\n            <Checkbox\n              aria-invalid={invalid}\n              checked={!indeterminate && (option.checked ?? false)}\n              disabled={option.disabled || disabled}\n              id={optionId}\n              indeterminate={indeterminate}\n              onChange={event => onCheckboxChange(event.currentTarget.checked, parentIndex, index)}\n              ref={index === 0 ? ref : undefined}\n            />\n            <Label htmlFor={optionId}>{option.label}</Label>\n          </Utility>\n          {option?.children && (\n            <Utility vFlex vFlexCol vMarginLeft={16} tag=\"ul\">\n              <CheckboxGroup\n                disabled={option.disabled || disabled}\n                invalid={invalid}\n                onCheckboxChange={onCheckboxChange}\n                options={option.children}\n                parentId={optionId}\n                parentIndex={(parentIndex || 0) + index}\n              />\n            </Utility>\n          )}\n        </Utility>\n      );\n    })\n);\n\nCheckboxGroup.displayName = 'CheckboxGroup';\n\nexport const ErrorIndeterminateGroupCheckbox = () => {\n  const [invalid, setInvalid] = useState(false);\n  const [options, setOptions] = useState(defaultOptions);\n  const firstFocusableCheckbox = useRef<HTMLInputElement | null>(null);\n\n  const onCheckboxChange = (checked: boolean, parentIndex: number | undefined, childIndex: number) => {\n    // Initialize our new options array\n    const newOptions = [...options];\n\n    const checkboxGroup = newOptions[parentIndex === undefined ? childIndex : parentIndex];\n    const checkboxChild = checkboxGroup?.children && checkboxGroup?.children[childIndex];\n    // If parentIndex is undefined then it is a parent checkbox change\n    if (parentIndex === undefined) {\n      checkboxGroup.checked = checked;\n      checkboxGroup.children?.forEach(child => {\n        child.checked = checked;\n      });\n    }\n    // If children exist and they're all checked make sure the group is checked\n    if (checkboxChild) {\n      checkboxChild.checked = checked;\n      const allChildrenChecked = checkboxGroup.children?.every(child => child?.checked) || false;\n      checkboxGroup.checked = allChildrenChecked;\n    }\n\n    // Update the state\n    setOptions(newOptions);\n  };\n\n  const onSubmit = () => {\n    // Check if any of the checkboxes are not checked\n    const isInvalid = options.some(option => !option.checked);\n    // Set invalid state\n    setInvalid(isInvalid);\n    // If invalid focus on the first checkbox\n    if (isInvalid) firstFocusableCheckbox.current?.focus();\n  };\n\n  return (\n    <>\n      <fieldset aria-labelledby={`${id}-legend`} style={{ '--v-checkbox-group-gap': '8px' } as CSSProperties}>\n        <Label aria-describedby={`${id}-message`} id={`${id}-legend`} tag=\"legend\">\n          Group label\n        </Label>\n        <Utility tag=\"ul\" vFlex vFlexCol>\n          <CheckboxGroup\n            invalid={invalid}\n            onCheckboxChange={onCheckboxChange}\n            options={options}\n            parentId={id}\n            ref={firstFocusableCheckbox}\n          />\n        </Utility>\n        <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\" variant=\"body-3\">\n          {invalid && (\n            <>\n              <VisaErrorTiny />\n              This is required text that describes the error in more detail.\n            </>\n          )}\n        </InputMessage>\n      </fieldset>\n      <Button className=\"v-mt-12\" onClick={onSubmit}>\n        Submit\n      </Button>\n    </>\n  );\n};\n"
          },
          "name": "Error indeterminate checkbox group"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox groups",
          "url": {
            "iframe": "components/checkbox/group-horizontal-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/group-horizontal-checkbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'group-horizontal-checkbox';\n\nconst checkboxes = ['Label 1', 'Label 2', 'Label 3', 'Label 4'];\n\nexport const GroupHorizontalCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-legend`}>\n      <Label className=\"v-label\" id={`${id}-legend`} tag=\"legend\">\n        Group label\n      </Label>\n      <Utility tag=\"ul\" vFlex vFlexRow vFlexWrap vGap={24}>\n        {checkboxes.map((checkbox, index) => (\n          <Utility key={`${id}-option-${index}`} tag=\"li\" vAlignItems=\"center\" vFlex vGap={2}>\n            <Checkbox id={`${id}-option-${index}`} />\n            <Label htmlFor={`${id}-option-${index}`}>{checkbox}</Label>\n          </Utility>\n        ))}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Horizontal checkbox group"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox panels",
          "url": {
            "iframe": "components/checkbox/with-description-panel-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/with-description-panel-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, CheckboxPanel, InputMessage, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'with-description-panel-checkbox';\n\nexport const WithDescriptionPanelCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <CheckboxPanel htmlFor={id} className=\"v-align-items-start\">\n        <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n          <Checkbox id={id} name={id} className=\"v-flex-shrink-0\" />\n          <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n            Label\n            <InputMessage id={`${id}-message`}>\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          </Utility>\n        </Utility>\n      </CheckboxPanel>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Checkbox panel"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox panels",
          "url": {
            "iframe": "components/checkbox/without-description-panel-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/without-description-panel-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, CheckboxPanel, Utility, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'without-description-panel-checkbox';\n\nexport const WithoutDescriptionPanelCheckbox = () => {\n  return (\n    <UtilityFragment vAlignItems=\"start\">\n      <CheckboxPanel htmlFor={id}>\n        <Utility style={{ inlineSize: '100%' }} vAlignItems=\"center\" vFlex vGap={2}>\n          <Checkbox className=\"v-flex-shrink-0\" id={id} name={id} />\n          Label\n        </Utility>\n      </CheckboxPanel>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Checkbox panel without description"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox panels",
          "url": {
            "iframe": "components/checkbox/disabled-panel-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/disabled-panel-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, CheckboxPanel, InputMessage, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-panel-disabled';\n\nexport const DisabledPanelCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <CheckboxPanel className=\"v-align-items-start\" htmlFor={id}>\n        <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n          <Checkbox className=\"v-flex-shrink-0\" disabled id={id} name={id} />\n          <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n            Label\n            <InputMessage id={`${id}-message`}>\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          </Utility>\n        </Utility>\n      </CheckboxPanel>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Disabled checkbox panel"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox panels group",
          "url": {
            "iframe": "components/checkbox/group-panel-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/group-panel-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, CheckboxPanel, InputMessage, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'group-panel-checkbox';\n\nconst checkboxes = [\n  { label: 'Label 1', message: 'This is optional text that describes the label in more detail.' },\n  { label: 'Label 2', message: 'This is optional text that describes the label in more detail.' },\n  { label: 'Label 3', message: 'This is optional text that describes the label in more detail.' },\n];\n\nexport const GroupPanelCheckbox = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-legend`}>\n      <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n        Group Label\n      </Typography>\n      <Utility vFlex vFlexCol vGap={8}>\n        {checkboxes.map((checkbox, index) => {\n          const optionId = `${id}-option-${index}`;\n          const messageId = `${optionId}-option-${index}`;\n          return (\n            <CheckboxPanel className=\"v-align-items-start\" key={optionId} htmlFor={optionId}>\n              <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n                <Checkbox aria-describedby={messageId} className=\"v-flex-shrink-0\" id={optionId} name={optionId} />\n                <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n                  {checkbox.label}\n                  <InputMessage id={messageId}>{checkbox.message}</InputMessage>\n                </Utility>\n              </Utility>\n            </CheckboxPanel>\n          );\n        })}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Checkbox panel group"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox panels group",
          "url": {
            "iframe": "components/checkbox/error-group-panel-checkbox",
            "github": "apps/workshop/src/examples/components/checkbox/error-group-panel-checkbox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useRef, useState, type FormEvent } from 'react';\nimport { Button, Checkbox, CheckboxPanel, InputMessage, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-group-panel-checkbox';\n\ntype Option = {\n  checked: boolean;\n  label: string;\n  value: string;\n  message?: string;\n};\n\nconst defaultOptions: Option[] = [\n  {\n    checked: false,\n    label: 'Label 1',\n    message: 'This is optional text that describes the label in more detail.',\n    value: 'label-1',\n  },\n  {\n    checked: false,\n    label: 'Label 2',\n    message: 'This is optional text that describes the label in more detail.',\n    value: 'label-2',\n  },\n  {\n    checked: false,\n    label: 'Label 3',\n    message: 'This is optional text that describes the label in more detail.',\n    value: 'label-3',\n  },\n];\n\nexport const ErrorPanelGroupCheckbox = () => {\n  const checkboxRefs = useRef<(HTMLInputElement | null)[]>([]);\n  const [options, setOptions] = useState(defaultOptions);\n  const [invalid, setInvalid] = useState(false);\n\n  const onCheckboxChange = (event: FormEvent<HTMLInputElement>, index: number) => {\n    const { checked } = event.currentTarget;\n    const newOptions = [...options];\n    newOptions[index].checked = checked;\n    setOptions(newOptions);\n  };\n\n  const onSubmit = () => {\n    // Check if any of the checkbox are checked\n    const isInvalid = !options.some(checkbox => checkbox.checked);\n    // Set invalid state\n    setInvalid(isInvalid);\n    // If invalid focus on the first checkbox\n    if (isInvalid) checkboxRefs.current[0]?.focus();\n  };\n\n  return (\n    <>\n      <fieldset aria-labelledby={`${id}-legend`}>\n        <Typography aria-describedby={`${id}-message`} id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n          Group Label\n        </Typography>\n        <Utility vFlex vFlexCol vGap={8}>\n          {options.map((option, index) => {\n            const optionId = `${id}-option-${index}`;\n            const messageId = `${optionId}-message`;\n            return (\n              <Utility<'label'> element={<CheckboxPanel />} htmlFor={optionId} key={optionId} vAlignItems=\"start\">\n                <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n                  <Checkbox\n                    aria-describedby={messageId}\n                    aria-invalid={invalid}\n                    checked={option.checked}\n                    className=\"v-flex-shrink-0\"\n                    id={optionId}\n                    onChange={event => onCheckboxChange(event, index)}\n                    ref={ref => {\n                      checkboxRefs.current[index] = ref;\n                    }}\n                    value={option.value}\n                  />\n                  <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n                    {option.label}\n                    <InputMessage id={messageId}>{option.message}</InputMessage>\n                  </Utility>\n                </Utility>\n              </Utility>\n            );\n          })}\n        </Utility>\n        <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\" variant=\"body-3\">\n          {invalid && (\n            <>\n              <VisaErrorTiny />\n              This is required text that describes the error in more detail.\n            </>\n          )}\n        </InputMessage>\n      </fieldset>\n      <Button onClick={onSubmit}>Submit</Button>\n    </>\n  );\n};\n"
          },
          "name": "Checkbox panel group with error"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Custom checkboxes",
          "url": {
            "iframe": "components/checkbox/reusable",
            "github": "apps/workshop/src/examples/components/checkbox/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  CheckboxPanel,\n  type CheckboxProperties,\n  InputMessage,\n  Label,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Reusable Checkbox Component Props\nexport interface ReusableCheckboxProps extends Omit<CheckboxProperties<'input'>, 'children' | 'tag'> {\n  children?: never;\n  description?: string;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  panel?: boolean;\n}\n\n// Main Reusable Checkbox Component\nexport const NovaCheckbox = ({\n  checked = false,\n  description,\n  disabled = false,\n  id: idProp,\n  indeterminate = false,\n  invalid = false,\n  label = '',\n  message,\n  panel = false,\n  required = false,\n  onChange,\n  ...remainingInputProps\n}: ReusableCheckboxProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  // Calculate aria-describedby\n  const inputDescribedBy = useMemo(() => {\n    const ids: string[] = [];\n    if (message) ids.push(`${id}-message`);\n    if (description) ids.push(`${id}-description`);\n    return ids.length > 0 ? ids.join(' ') : undefined;\n  }, [message, description, id]);\n\n  const checkboxContent = (\n    <>\n      <Utility vAlignItems={panel && description ? 'start' : undefined} vFlex>\n        <Checkbox\n          aria-describedby={inputDescribedBy}\n          aria-required={required ? true : undefined}\n          checked={checked}\n          disabled={disabled}\n          id={`${id}-input`}\n          indeterminate={indeterminate}\n          aria-invalid={invalid}\n          onChange={onChange}\n          required={required}\n          {...remainingInputProps}\n        />\n        <Utility vFlex vFlexCol vGap={2} vMarginVertical={10}>\n          <Label htmlFor={`${id}-input`}>{label}</Label>\n          {description && <InputMessage id={`${id}-description`}>{description}</InputMessage>}\n        </Utility>\n      </Utility>\n    </>\n  );\n\n  return (\n    <>\n      {panel ? <CheckboxPanel>{checkboxContent}</CheckboxPanel> : checkboxContent}\n      <UtilityFragment vMarginTop={4}>\n        <InputMessage\n          aria-atomic={invalid ? true : undefined}\n          aria-live={invalid ? 'assertive' : undefined}\n          id={`${id}-message`}\n        >\n          {invalid && message && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </UtilityFragment>\n    </>\n  );\n};\n\n// export default NovaCheckbox;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  description: string;\n  disabled: boolean;\n  errorMessage: string;\n  invalid: boolean;\n  label: string;\n  panel: boolean;\n  required: boolean;\n}\n\n// Demo Component\nexport const ReusableCheckboxDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    invalid: false,\n    label: 'Label',\n    panel: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <NovaCheckbox\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : undefined}\n        panel={customizations.panel}\n        required={customizations.required}\n      />\n\n      <Utility vMarginTop={24}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Panel\"\n                checked={formValues.panel}\n                onChange={e => handleInputChange('panel', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </Utility>\n    </div>\n  );\n};\nexport default ReusableCheckboxDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable checkbox"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Custom checkboxes",
          "url": {
            "iframe": "components/checkbox/reusable-group",
            "github": "apps/workshop/src/examples/components/checkbox/reusable-group.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputMessage, Typography, Utility } from '@visa/nova-react';\nimport { useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaCheckbox } from './reusable';\n\n// Checkbox Group Type\nexport interface CheckboxGroup {\n  checked?: boolean;\n  children?: CheckboxGroup[];\n  description?: string;\n  disabled?: boolean;\n  label: string;\n}\n\n// Nova Checkbox Group Component Props\nexport interface NovaCheckboxGroupProps {\n  checkboxes?: CheckboxGroup[];\n  description?: string;\n  disabled?: boolean;\n  id?: string;\n  inline?: boolean;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  onCheckboxesChange?: (checkboxes: CheckboxGroup[]) => void;\n  panel?: boolean;\n  required?: boolean;\n  root?: boolean;\n}\n\n// Main Nova Checkbox Group Component\nexport const NovaCheckboxGroup = ({\n  checkboxes: checkboxesProp = [],\n  description,\n  disabled = false,\n  id: idProp,\n  inline = false,\n  invalid = false,\n  label = '',\n  message,\n  onCheckboxesChange,\n  panel = false,\n  required = false,\n  root = true,\n}: NovaCheckboxGroupProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const [checkboxes, setCheckboxes] = useState<CheckboxGroup[]>(checkboxesProp);\n\n  // Update internal state when prop changes\n  useMemo(() => {\n    setCheckboxes(checkboxesProp);\n  }, [checkboxesProp]);\n\n  // Calculate aria-labelledby for fieldset\n  const fieldsetLabelledBy = useMemo(() => {\n    const ids: string[] = [`${id}-legend`];\n    if (description) ids.push(`${id}-description`);\n    return ids.join(' ');\n  }, [description, id]);\n\n  // Helper: Check if all children are checked\n  const getChecked = (group: CheckboxGroup): boolean => {\n    const { children } = group;\n    if (!children?.length) return !!group.checked;\n    return children.every(c => c.checked);\n  };\n\n  // Helper: Check if should be indeterminate\n  const getIndeterminate = (group: CheckboxGroup, everyChecked: boolean): boolean => {\n    const { children } = group;\n    if (!children?.length) return false;\n    return children.some(c => c.checked || recursivelyLookForCheckedChildren(c.children)) && !everyChecked;\n  };\n\n  // Helper: Recursively look for checked children\n  const recursivelyLookForCheckedChildren = (children?: CheckboxGroup[]): boolean => {\n    if (!children?.length) return false;\n    for (const child of children) {\n      if (child.checked) {\n        return true;\n      }\n      if (child.children?.length) {\n        if (recursivelyLookForCheckedChildren(child.children)) {\n          return true;\n        }\n      }\n    }\n    return false;\n  };\n\n  // Helper: Update all children recursively\n  const updateChildrenRecursively = (children: CheckboxGroup[], checked: boolean): CheckboxGroup[] => {\n    return children.map(child => ({\n      ...child,\n      checked,\n      children: child.children?.length ? updateChildrenRecursively(child.children, checked) : child.children,\n    }));\n  };\n\n  // Event: Handle checkbox change\n  const handleCheckChange = (checked: boolean, index: number) => {\n    const newCheckboxes = [...checkboxes];\n    const box = newCheckboxes[index];\n    box.checked = checked;\n    if (box.children?.length) {\n      box.children = updateChildrenRecursively(box.children, checked);\n    }\n    setCheckboxes(newCheckboxes);\n    onCheckboxesChange?.(newCheckboxes);\n  };\n\n  // Event: Handle nested group change\n  const handleGroupChange = (newGroup: CheckboxGroup[], groupIndex: number) => {\n    const newCheckboxes = [...checkboxes];\n    const group = newCheckboxes[groupIndex];\n    if (group) {\n      group.children = [...newGroup];\n      // Update parent's checked state based on children\n      group.checked = newGroup.every(c => c.checked);\n    }\n    setCheckboxes(newCheckboxes);\n    onCheckboxesChange?.(newCheckboxes);\n  };\n\n  // Render checkbox list content\n  const checkboxContent = (\n    <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>\n      <Utility vFlex vFlexCol={!inline} vMarginLeft={root ? undefined : 32}>\n        {checkboxes.map((checkbox, i) => {\n          const hasChildren = checkbox?.children?.length;\n          const everythingChecked = getChecked(checkbox);\n          const indeterminate = getIndeterminate(checkbox, everythingChecked);\n\n          return (\n            <li key={`${id}-checkbox-${i}`}>\n              <Utility vFlex vFlexCol>\n                <NovaCheckbox\n                  checked={(!indeterminate && checkbox.checked) || (hasChildren ? everythingChecked : false)}\n                  disabled={disabled || checkbox.disabled}\n                  indeterminate={hasChildren ? indeterminate : false}\n                  invalid={invalid}\n                  label={checkbox.label}\n                  onChange={e => handleCheckChange(e.target.checked, i)}\n                  panel={panel}\n                />\n                {hasChildren && (\n                  <NovaCheckboxGroup\n                    checkboxes={checkbox.children!}\n                    disabled={disabled || checkbox.disabled}\n                    id={`${id}-checkbox-${i}-group`}\n                    invalid={invalid}\n                    onCheckboxesChange={newGroup => handleGroupChange(newGroup, i)}\n                    panel={panel}\n                    root={false}\n                  />\n                )}\n              </Utility>\n            </li>\n          );\n        })}\n      </Utility>\n    </ul>\n  );\n\n  if (!root) return checkboxContent;\n\n  return (\n    <fieldset aria-labelledby={fieldsetLabelledBy}>\n      <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label-large\">\n        {label}\n        {required ? ' (required)' : ''}\n      </Typography>\n\n      {description && <InputMessage id={`${id}-description`}>{description}</InputMessage>}\n\n      {checkboxContent}\n\n      <InputMessage\n        aria-atomic={invalid ? true : undefined}\n        aria-live={invalid ? 'assertive' : undefined}\n        id={`${id}-message`}\n      >\n        {invalid && <VisaErrorTiny />}\n        {message && message}\n      </InputMessage>\n    </fieldset>\n  );\n};\n\n// export default NovaCheckboxGroup;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  checkboxes: string;\n  description: string;\n  disabled: boolean;\n  errorMessage: string;\n  inline: boolean;\n  invalid: boolean;\n  label: string;\n  panel: boolean;\n  required: boolean;\n}\n\n// Demo Component\nexport const NovaCheckboxGroupDemo = () => {\n  const checkboxes: CheckboxGroup[] = [\n    {\n      description: 'This is optional text that describes the label in more detail.',\n      checked: false,\n      label: 'L1 label 1',\n    },\n    {\n      checked: false,\n      label: 'L1 label 2',\n      children: [\n        {\n          checked: false,\n          label: 'L2 label 1',\n        },\n        {\n          checked: false,\n          label: 'L2 label 2',\n          children: [\n            {\n              checked: false,\n              label: 'L3 label 1',\n            },\n            {\n              checked: false,\n              label: 'L3 label 2',\n              children: [\n                {\n                  checked: false,\n                  label: 'L4 label 1',\n                },\n                {\n                  checked: false,\n                  label: 'L4 label 2',\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    checkboxes: JSON.stringify(checkboxes, null, 4),\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    inline: false,\n    invalid: false,\n    label: 'Group label',\n    panel: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'checkboxes'> & { checkboxes: CheckboxGroup[] }\n  >({\n    ...defaultCustomizations,\n    checkboxes,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedCheckboxes = JSON.parse(formValues.checkboxes || '[]') as CheckboxGroup[];\n      setCustomizations({\n        ...formValues,\n        checkboxes: parsedCheckboxes,\n      });\n    } catch (error) {\n      console.error('Invalid JSON for checkboxes:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      checkboxes,\n    });\n  };\n\n  return (\n    <div>\n      <NovaCheckboxGroup\n        checkboxes={customizations.checkboxes}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        inline={customizations.inline}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : undefined}\n        panel={customizations.panel}\n        required={customizations.required}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <NovaInput<'textarea'>\n                blockSize=\"320px\"\n                id=\"checkboxes-input\"\n                label=\"Checkboxes\"\n                onChange={e => handleInputChange('checkboxes', e.target.value)}\n                resizable\n                textarea\n                value={formValues.checkboxes}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Inline\"\n                checked={formValues.inline}\n                onChange={e => handleInputChange('inline', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Panel\"\n                checked={formValues.panel}\n                onChange={e => handleInputChange('panel', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaCheckboxGroupDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable checkbox group"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Checkbox",
          "selector": "<Checkbox />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive element enabling users to select one or more independent options from a group."
        },
        {
          "order": 2,
          "name": "Checkboxpanel",
          "selector": "<CheckboxPanel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container to be used with checkbox component to add border and background color."
        }
      ],
      "properties": [
        {
          "name": "indeterminate",
          "section": "Checkbox",
          "data": {
            "name": "indeterminate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Whether a checkbox is indeterminate state, only allowable on \"input\" tag types. This should only be set to true if checked is false."
          }
        },
        {
          "name": "tag",
          "section": "Checkbox",
          "data": {
            "name": "tag",
            "type": "\"symbol\" , \"object\" , \"a\" , \"abbr\" , \"address\" , \"area\" , \"article\" , \"aside\" , \"audio\" , \"b\" , \"base\" , \"bdi\" , \"bdo\" , \"big\" , \"blockquote\" , \"body\" , \"br\" , \"button\" , \"canvas\" , ... 159 more ... , ComponentType",
            "default": "input",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "colorScheme",
          "section": "Checkboxpanel",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Checkboxpanel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Checkboxpanel",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "chip",
      "version": "0.0.1",
      "description": "Compact elements used to filter content or display user input.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Selection chips",
          "description": "",
          "order": 1
        },
        {
          "name": "Removable chips",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom chips",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/default-selection-chip",
            "github": "apps/workshop/src/examples/components/chip/default-selection-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-selection-chip';\n\nexport const DefaultSelectionChip = () => {\n  return (\n    <Chip<'label'> chipType=\"selection\" htmlFor={id} tag=\"label\">\n      Label\n      <Checkbox id={id} />\n    </Chip>\n  );\n};\n"
          },
          "name": "Default selection chip"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/selected-selection-chip",
            "github": "apps/workshop/src/examples/components/chip/selected-selection-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'selected-selection-chip';\n\nexport const SelectedSelectionChip = () => {\n  return (\n    <Chip<'label'> chipType=\"selection\" htmlFor={id} tag=\"label\">\n      Label\n      <Checkbox defaultChecked id={id} />\n    </Chip>\n  );\n};\n"
          },
          "name": "Selected selection chip"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/multi-line-selection-chip",
            "github": "apps/workshop/src/examples/components/chip/multi-line-selection-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-line-selection-chip';\n\nexport const MultiLineSelectionChip = () => {\n  return (\n    <Chip<'label'> chipType=\"selection\" htmlFor={id} tag=\"label\">\n      This is a chip label\n      <br />\n      that wraps on\n      <br />\n      multiple lines\n      <Checkbox id={id} />\n    </Chip>\n  );\n};\n"
          },
          "name": "Multi-line selection chip"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/disabled-selection-chip",
            "github": "apps/workshop/src/examples/components/chip/disabled-selection-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-selection-chip';\n\nexport const DisabledSelectionChip = () => {\n  return (\n    <Chip<'label'> chipType=\"selection\" htmlFor={id} tag=\"label\">\n      Label\n      <Checkbox disabled id={id} />\n    </Chip>\n  );\n};\n"
          },
          "name": "Disabled selection chip"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/checked-disabled-selection-chip",
            "github": "apps/workshop/src/examples/components/chip/checked-disabled-selection-chip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checked-disabled-selection-chip';\n\nexport const CheckedDisabledSelectionChip = () => {\n  return (\n    <Chip<'label'> chipType=\"selection\" htmlFor={id} tag=\"label\">\n      Label\n      <Checkbox defaultChecked disabled id={id} />\n    </Chip>\n  );\n};\n"
          },
          "name": "Disabled selected selection chip"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Selection chips",
          "url": {
            "iframe": "components/chip/selection-group-chip",
            "github": "apps/workshop/src/examples/components/chip/selection-group-chip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Chip, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'selection-group-chip';\n\nconst chips = ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6', 'Label 7'];\n\nexport const SelectionGroupChip = () => {\n  return (\n    <Utility vFlex vFlexWrap vGap={8} style={{ inlineSize: '50%' }}>\n      {chips.map((chip, index) => (\n        <Chip<'label'> chipType=\"selection\" htmlFor={`${id}-${index}`} key={`${id}-${index}`} tag=\"label\">\n          <span>{chip}</span>\n          <Checkbox id={`${id}-${index}`} />\n        </Chip>\n      ))}\n    </Utility>\n  );\n};\n"
          },
          "name": "Selection chip group"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/default-removable-chip",
            "github": "apps/workshop/src/examples/components/chip/default-removable-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip } from '@visa/nova-react';\n\nexport const DefaultRemovableChip = () => {\n  return (\n    <Chip>\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Default removable chip"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/removable-icon-chip",
            "github": "apps/workshop/src/examples/components/chip/removable-icon-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip } from '@visa/nova-react';\n\nexport const RemovableIconChip = () => {\n  return (\n    <Chip>\n      <VisaAccountTiny />\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Removable chip with icon"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/removable-avatar-chip",
            "github": "apps/workshop/src/examples/components/chip/removable-avatar-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Avatar, Button, Chip } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\n\nexport const RemovableAvatarChip = () => {\n  return (\n    <Chip>\n      <Avatar<'img'> aria-label=\"Alex Miller\" src={BASE_URL + '/alex-miller-stock.png'} tag=\"img\" />\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Removable chip with avatar"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/disabled-removable-chip",
            "github": "apps/workshop/src/examples/components/chip/disabled-removable-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-line-selection-chip';\n\nexport const DisabledRemovableChip = () => {\n  return (\n    <Chip>\n      <label className=\"v-label\" htmlFor={id}>Label</label> \n      <Button aria-label=\"clear\" colorScheme=\"tertiary\" id={id} disabled iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Disabled removable chip"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/compact-removable-chip",
            "github": "apps/workshop/src/examples/components/chip/compact-removable-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip } from '@visa/nova-react';\n\nexport const CompactRemovableChip = () => {\n  return (\n    <Chip chipSize=\"compact\">\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Compact removable chip"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/compact-removable-icon-chip",
            "github": "apps/workshop/src/examples/components/chip/compact-removable-icon-chip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip } from '@visa/nova-react';\n\nexport const CompactRemovableIconChip = () => {\n  return (\n    <Chip chipSize=\"compact\">\n      <VisaAccountTiny />\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Compact removable chip with icon"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/compact-removable-avatar-chip",
            "github": "apps/workshop/src/examples/components/chip/compact-removable-avatar-chip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Avatar, Button, Chip } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\n\nexport const CompactRemovableAvatarChip = () => {\n  return (\n    <Chip chipSize=\"compact\">\n      <Avatar<'img'> aria-label=\"Alex Miller\" src={BASE_URL + '/alex-miller-stock.png'} tag=\"img\" />\n      <span>Label</span>\n      <Button aria-label=\"clear Label\" colorScheme=\"tertiary\" iconButton subtle>\n        <VisaClearAltTiny />\n      </Button>\n    </Chip>\n  );\n};\n"
          },
          "name": "Compact removable chip with avatar"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/removable-group-chip",
            "github": "apps/workshop/src/examples/components/chip/removable-group-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { useState } from 'react';\nimport { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip, Utility } from '@visa/nova-react';\n\nexport const RemovableGroupChip = () => {\n  const initialChips = ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6', 'Label 7', 'Label 8'];\n  const [chips, setChips] = useState(initialChips);\n\n  const handleRemove = (chipToRemove: string) => {\n    setChips(chips => chips.filter(chip => chip !== chipToRemove));\n  };\n\n  const resetChips = () => {\n    setChips(initialChips);\n  };\n\n  return (\n    <>\n      <Utility vFlex vFlexWrap vGap={8}>\n        {chips.map((chip, index) => (\n          <Chip key={index}>\n            {chip}\n            <Button iconButton colorScheme=\"tertiary\" subtle aria-label={`Clear ${chip}`} onClick={() => handleRemove(chip)}>\n              <VisaClearAltTiny />\n            </Button>\n          </Chip>\n        ))}\n      </Utility>\n      <Utility vMarginTop={12}>\n        <Button onClick={resetChips}>Reset</Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Removable chip group"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Removable chips",
          "url": {
            "iframe": "components/chip/compact-removable-group-chip",
            "github": "apps/workshop/src/examples/components/chip/compact-removable-group-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { useState } from 'react';\nimport { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Chip, Utility } from '@visa/nova-react';\n\nexport const CompactRemovableGroupChip = () => {\n  const initialChips = ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6'];\n  const [chips, setChips] = useState(initialChips);\n\n  const handleRemove = (chipToRemove: string) => {\n    setChips(chips => chips.filter(chip => chip !== chipToRemove));\n  };\n\n  const resetChips = () => {\n    setChips(initialChips);\n  };\n\n  return (\n    <>\n      <Utility vFlex vFlexWrap vGap={8}>\n        {chips.map((chip, index) => (\n          <Chip chipSize=\"compact\" key={index}>\n            {chip}\n            <Button iconButton colorScheme=\"tertiary\" subtle aria-label={`Clear ${chip}`} onClick={() => handleRemove(chip)}>\n              <VisaClearAltTiny />\n            </Button>\n          </Chip>\n        ))}\n      </Utility>\n      <Utility vMarginTop={12}>\n        <Button onClick={resetChips}>Reset</Button>\n      </Utility>\n    </>\n  );\n};"
          },
          "name": "Compact removable chip group"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Custom chips",
          "url": {
            "iframe": "components/chip/static-chip",
            "github": "apps/workshop/src/examples/components/chip/static-chip.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Chip } from '@visa/nova-react';\n\nexport const StaticChip = () => {\n  return (\n    <Chip<'label'> tag=\"label\">\n      Label\n    </Chip>\n  );\n};\n"
          },
          "name": "Static chip"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Chip",
          "selector": "<Chip />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Compact elements used to filter content or display user input."
        }
      ],
      "properties": [
        {
          "name": "chipSize",
          "section": "Chip",
          "data": {
            "name": "chipSize",
            "type": "\"compact\"",
            "default": "",
            "required": "false",
            "description": "Chip Size"
          }
        },
        {
          "name": "chipType",
          "section": "Chip",
          "data": {
            "name": "chipType",
            "type": "\"selection\"",
            "default": "",
            "required": "false",
            "description": "Chip Type"
          }
        },
        {
          "name": "tag",
          "section": "Chip",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "color-selector",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default color selectors",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default color selectors",
          "url": {
            "iframe": "components/color-selector/color-input",
            "github": "apps/workshop/src/examples/components/color-selector/color-input.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n} from '@floating-ui/react';\nimport { Input, Label, Button, Tooltip, Utility, UtilityFragment } from '@visa/nova-react';\nimport { VisaAccessibilityTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\n\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'color-input';\n\nexport const ColorInput = () => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(2)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement: 'right',\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  return (\n    <Utility vFlex vAlignItems=\"center\" vGap={6}>\n      <UtilityFragment vFlexGrow0 style={{ flexBasis: '5%' }}>\n        <Input id={id} type=\"color\" />\n      </UtilityFragment>\n      <Label htmlFor={id}>Label</Label>\n      <Utility vAlignItems=\"center\" vFlex vFlexCol vGap={2}>\n      <Button \n        aria-labelledby={`${id}-label`}\n        aria-label=\"Color selector accessibility information\"\n        colorScheme=\"tertiary\"\n        iconButton\n        ref={refs.setReference} {...getReferenceProps()}>\n          <VisaAccessibilityTiny rtl />\n        </Button>\n        {isOpen && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            left: x,\n            position: strategy,\n            top: y,\n            width: 'fit-content',\n          }}\n          {...getFloatingProps()}\n        >\n          For RGB, use values between 0-255. For HSL, use H values between 0-359, S and L values between 0-100%. For hex,\n          use the format #RRGGBB and values between 0-9 or A-F.\n        </Tooltip>\n      )}\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default color selector"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "input",
          "type": "related",
          "selector": "<Input />",
          "description": ""
        }
      ],
      "properties": []
    },
    {
      "name": "combobox",
      "version": "0.0.1",
      "description": "Dropdown menu enabling users to enter text or select items from a list.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default Comboboxes",
          "description": "",
          "order": 1
        },
        {
          "name": "Combobox behaviors",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom comboboxes",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/no-autocomplete-combobox",
            "github": "apps/workshop/src/examples/components/combobox/no-autocomplete-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const NoAutocompleteCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    items: items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-1\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`no-autocomplete-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Default combobox"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/pre-selected-combobox",
            "github": "apps/workshop/src/examples/components/combobox/pre-selected-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const PreSelectedCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    initialInputValue: 'Option A',\n    items: items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-2\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`pre-selected-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with selected option"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/inline-message-combobox",
            "github": "apps/workshop/src/examples/components/combobox/inline-message-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const InlineMessageCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    items: items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-describedby=\"combobox-inline-message\"\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-3\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n          {!isOpen && (\n            <InputMessage id=\"combobox-inline-message\">\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          )}\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`inline-message-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with inline message"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/clear-button-combobox",
            "github": "apps/workshop/src/examples/components/combobox/clear-button-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId, useState, type FocusEvent } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const ClearButtonCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    selectItem,\n    highlightedIndex,\n    isOpen,\n    inputValue,\n  } = useCombobox({\n    id,\n    initialInputValue: 'Option A',\n    items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  const [focused, setFocused] = useState(false);\n\n  const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n    if (!event.currentTarget.contains(event.relatedTarget)) {\n      setFocused(false);\n    }\n  };\n\n  const onClear = () => selectItem(null);\n  const showClearButton = inputValue.length > 0 && focused;\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer\n              onBlur={e => handleBlur(e)}\n              onFocus={() => {\n                setFocused(true);\n              }}\n            >\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-4\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen && items.length > 0, 'aria-owns': listboxId })}\n              />\n              {showClearButton && (\n                <Button\n                  aria-label=\"clear\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={onClear}\n                  subtle\n                >\n                  <VisaClearAltTiny />\n                </Button>\n              )}\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`clear-button-combobox-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with clear button"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/leading-icon-combobox",
            "github": "apps/workshop/src/examples/components/combobox/leading-icon-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaSearchLow } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const LeadingIconCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <VisaSearchLow />\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-5\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen && items.length > 0, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`clear-button-combobox-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with leading icon"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/error-combobox",
            "github": "apps/workshop/src/examples/components/combobox/error-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId, useState } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\n/**\n * NOTE: Error styling relies on the Label and InputContainer being direct siblings within the\n * DropdownContainer. Wrapping either element in an extra container (e.g., a <div>) will\n * break the sibling CSS selector and prevent error styles from being applied.\n *\n * Forcing error styles with utility classes like `v-input-error` on a\n * parent will cause non-listbox text content (e.g., a <span>subtitle</span> inside a\n * ListboxItem) to also turn red, which may not be the desired behavior.\n *\n * Keep the Label and InputContainer as direct children of DropdownContainer to ensure\n * error states render correctly.\n */\nexport const ErrorCombobox = () => {\n  const id = useId();\n  const [errorState, setErrorState] = useState(false);\n\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    selectItem,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n    selectedItem,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    stateReducer,\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Utility vFlexCol vGap={12}>\n      <Combobox>\n        <DropdownContainer className=\"v-flex v-flex-col v-gap-4\">\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <InputContainer className=\"v-flex-row\">\n            <Input\n              aria-describedby=\"input-error-message\"\n              aria-haspopup=\"listbox\"\n              aria-invalid={errorState ? 'true' : 'false'}\n              name=\"text-input-field-6\"\n              type=\"text\"\n              {...getInputProps({\n                'aria-expanded': isOpen && items.length > 0,\n                'aria-owns': listboxId,\n                onChange: () => selectItem(null),\n              })}\n            />\n            <Button\n              aria-label=\"expand\"\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              iconButton\n              {...getToggleButtonProps()}\n            >\n              {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n            </Button>\n          </InputContainer>\n          {errorState && !isOpen && (\n            <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id=\"input-error-message\" role=\"alert\">\n              <VisaErrorTiny />\n              This is required text that describes the error in more detail.\n            </InputMessage>\n          )}\n        </DropdownContainer>\n        <ListboxContainer>\n          <Listbox id={listboxId} {...listboxProps}>\n            {items.map((item, index) => (\n              <ListboxItem\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                key={`error-combobox-${index}`}\n                {...getItemProps({\n                  'aria-selected': inputValue === item.value,\n                  index,\n                  item,\n                })}\n              >\n                <UtilityFragment vFlexShrink0>\n                  <Radio tag=\"span\" />\n                </UtilityFragment>\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </ListboxContainer>\n      </Combobox>\n      <Utility vFlex vGap={12}>\n        <Button onClick={() => (!inputValue && !selectedItem ? setErrorState(true) : setErrorState(false))}>\n          Submit\n        </Button>\n        <Button\n          colorScheme=\"secondary\"\n          onClick={() => {\n            setErrorState(false);\n            selectItem(null);\n          }}\n        >\n          Reset\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Combobox with error"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/read-only-combobox",
            "github": "apps/workshop/src/examples/components/combobox/read-only-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { Button, Combobox, DropdownContainer, Input, InputContainer, Label, Listbox, ListboxContainer, ListboxItem, Radio, UtilityFragment } from '@visa/nova-react';\nimport { useCombobox } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const ReadOnlyCombobox = () => {\n  const id = useId();\n  const { getInputProps, getLabelProps, getMenuProps, getItemProps, getToggleButtonProps, inputValue } = useCombobox({\n    id,\n    items: items,\n    itemToString,\n    initialInputValue: 'Option A',\n  });\n\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                aria-owns=\"combobox-listbox-example-7\"\n                name=\"text-input-field-7\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': false, readOnly: true })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                disabled\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              key={`disabled-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Read-only combobox"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/disabled-combobox",
            "github": "apps/workshop/src/examples/components/combobox/disabled-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const DisabledCombobox = () => {\n  const id = useId();\n  const { getInputProps, getItemProps, getLabelProps, getMenuProps, getToggleButtonProps, inputValue, isOpen } =\n    useCombobox({\n      id,\n      items: items,\n      itemToString,\n      initialInputValue: 'Option A',\n    });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                disabled\n                name=\"text-input-field-8\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              key={`disabled-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Disabled combobox"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/item-disabled-combobox",
            "github": "apps/workshop/src/examples/components/combobox/item-disabled-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n      ...changes, // default Downshift new state changes on item selection.\n      highlightedIndex: state.highlightedIndex,\n    }\n    : changes;\n\nexport const ItemDisabledCombobox = () => {\n  const id = useId();\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    items: items,\n    itemToString,\n    stateReducer,\n    isItemDisabled: item => item.value === 'Option C', // This is just to mock the third option to be disabled\n  });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-9\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                <VisaChevronDownTiny />\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`item-disabled-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                'aria-disabled': item.value === 'Option C', // This is just to mock the third option to be disabled\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with disabled option"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Default Comboboxes",
          "url": {
            "iframe": "components/combobox/no-icon-combobox",
            "github": "apps/workshop/src/examples/components/combobox/no-icon-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId } from 'react';\n\ntype Item = { value: string };\n\nconst items: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const NoIconCombobox = () => {\n  const id = useId();\n  const { getInputProps, getItemProps, getLabelProps, getMenuProps, highlightedIndex, inputValue, isOpen } =\n    useCombobox({\n      id,\n      items: items,\n      itemToString,\n      stateReducer,\n    });\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-10\"\n                type=\"text\"\n                {...getInputProps({ 'aria-expanded': isOpen, 'aria-owns': listboxId })}\n              />\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`no-icon-example-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox without dropdown chevron"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Combobox behaviors",
          "url": {
            "iframe": "components/combobox/autocomplete-with-manual-selection-combobox",
            "github": "apps/workshop/src/examples/components/combobox/autocomplete-with-manual-selection-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId, useState } from 'react';\n\ntype Item = { value: string };\n\nconst defaultItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const filter = (item: Item, inputValue: string = '') =>\n  item.value.toLowerCase().includes(inputValue!.toLowerCase());\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n      ...changes, // default Downshift new state changes on item selection.\n      highlightedIndex: state.highlightedIndex,\n    }\n    : changes;\n\nexport const AutocompleteWithManualSelectionCombobox = () => {\n  const id = useId();\n  const [items, setItems] = useState(defaultItems);\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    onInputValueChange: ({ inputValue }) => {\n      setItems(defaultItems.filter(item => filter(item, inputValue)));\n    },\n    stateReducer,\n  });\n\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n  const resultsFound = items.length > 0;\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-12\"\n                type=\"text\"\n                {...getInputProps({\n                  'aria-expanded': isOpen,\n                  'aria-owns': listboxId,\n                })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.map((item, index) => (\n            <ListboxItem\n              className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n              key={`manual-autocomplete-combobox-${index}`}\n              {...getItemProps({\n                'aria-selected': inputValue === item.value,\n                index,\n                item,\n              })}\n            >\n              <UtilityFragment vFlexShrink0>\n                <Radio tag=\"span\" />\n              </UtilityFragment>\n              {item.value}\n            </ListboxItem>\n          ))}\n          {!resultsFound && (\n            <UtilityFragment vFlex vJustifyContent=\"center\" vPaddingVertical={8}>\n              <li>No results found.</li>\n            </UtilityFragment>\n          )}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with filterable menu and manual selection"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Combobox behaviors",
          "url": {
            "iframe": "components/combobox/autocomplete-with-automatic-selection-combobox",
            "github": "apps/workshop/src/examples/components/combobox/autocomplete-with-automatic-selection-combobox.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useId, useState } from 'react';\n\ntype Item = { value: string };\n\nconst defaultItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const filter = (item: Item, inputValue: string = '') =>\n  item.value.toLowerCase().includes(inputValue.toLowerCase());\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const stateReducer = <TItemType,>(\n  state: UseComboboxState<TItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<TItemType>\n) =>\n  // this prevents on mouse hover, the item in the list is automatic selected\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes, // default Downshift new state changes on item selection.\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\nexport const AutocompleteWithAutomaticSelectionCombobox = () => {\n  const id = useId();\n  const [items, setItems] = useState(defaultItems);\n  const {\n    isOpen,\n    getToggleButtonProps,\n    getLabelProps,\n    getInputProps,\n    getMenuProps,\n    getItemProps,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items: items,\n    itemToString,\n    onInputValueChange: ({ inputValue }) => {\n      setItems(defaultItems.filter(item => filter(item, inputValue)));\n      if (inputValue) setHighlightedIndex(0);\n    },\n    stateReducer,\n  });\n\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label</Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer>\n              <Input\n                aria-haspopup=\"listbox\"\n                name=\"text-input-field-11\"\n                type=\"text\"\n                {...getInputProps({\n                  'aria-autocomplete': 'list' as const,\n                  'aria-expanded': isOpen,\n                  'aria-owns': listboxId,\n                })}\n              />\n              <Button\n                aria-label=\"expand\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {items.length > 0 ? (\n            items.map((item, index) => (\n              <ListboxItem\n                key={`auto-autocomplete-combobox-${index}`}\n                {...getItemProps({\n                  index,\n                  item,\n                })}\n              >\n                <UtilityFragment vFlexShrink0>\n                  <Radio tag=\"span\" />\n                </UtilityFragment>\n                {item.value}\n              </ListboxItem>\n            ))\n          ) : (\n            <UtilityFragment vFlex vJustifyContent=\"center\" vPaddingVertical={8}>\n              <li>No results found.</li>\n            </UtilityFragment>\n          )}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Combobox with filterable menu and automatic selection"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Custom comboboxes",
          "url": {
            "iframe": "components/combobox/reusable",
            "github": "apps/workshop/src/examples/components/combobox/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import {\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaClearAltTiny,\n  VisaErrorTiny,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type UseComboboxState, type UseComboboxStateChangeOptions, useCombobox } from 'downshift';\nimport { type FocusEvent, type ReactNode, useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Types\nexport interface ComboboxOption<T = string> {\n  disabled?: boolean;\n  label: string;\n  value: T;\n}\n\n// Nova Combobox Component Props\nexport interface NovaComboboxProps<T = string> {\n  autoSelect?: boolean;\n  clearable?: boolean;\n  description?: string;\n  disabled?: boolean;\n  filterable?: boolean;\n  hideToggleButton?: boolean;\n  id?: string;\n  invalid?: boolean;\n  label?: string;\n  leadingIcon?: ReactNode;\n  message?: string;\n  onChange?: (value: T | null) => void;\n  options?: ComboboxOption<T>[];\n  readonly?: boolean;\n  required?: boolean;\n  value?: T | null;\n}\n\n// Item to string converter\nconst itemToString = <T,>(item: ComboboxOption<T> | null) => (item ? item.label : '');\n\n// State reducer to prevent mouse hover selection\nconst stateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) =>\n  type === useCombobox.stateChangeTypes.ItemMouseMove || type === useCombobox.stateChangeTypes.MenuMouseLeave\n    ? {\n        ...changes,\n        highlightedIndex: state.highlightedIndex,\n      }\n    : changes;\n\n// Main Nova Combobox Component\nexport const NovaCombobox = <T = string,>({\n  autoSelect = false,\n  clearable = false,\n  description,\n  disabled = false,\n  filterable = false,\n  hideToggleButton = false,\n  id: idProp,\n  invalid = false,\n  label = '',\n  leadingIcon,\n  message,\n  onChange,\n  options = [],\n  readonly = false,\n  required = false,\n  value: valueProp,\n  ...remainingProps\n}: NovaComboboxProps<T>) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const [focused, setFocused] = useState(false);\n  const [items, setItems] = useState(options);\n\n  // Find initial item from value prop\n  const initialItem = useMemo(\n    () => (valueProp !== null && valueProp !== undefined ? options.find(opt => opt.value === valueProp) || null : null),\n    [valueProp, options]\n  );\n\n  const {\n    getInputProps,\n    getItemProps,\n    getLabelProps,\n    getMenuProps,\n    getToggleButtonProps,\n    highlightedIndex,\n    inputValue,\n    isOpen,\n    selectItem,\n    selectedItem,\n    setHighlightedIndex,\n  } = useCombobox({\n    id: `${id}-combobox`,\n    items,\n    itemToString,\n    ...(initialItem && { initialSelectedItem: initialItem }),\n    stateReducer,\n    isItemDisabled: item => item.disabled || false,\n    onInputValueChange: ({ inputValue: newInputValue }) => {\n      if (filterable && newInputValue !== undefined) {\n        const filtered = options.filter(item => item.label.toLowerCase().includes(newInputValue.toLowerCase()));\n        setItems(filtered);\n        if (autoSelect && newInputValue) {\n          setHighlightedIndex(0);\n        }\n      }\n    },\n    onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {\n      onChange?.(newSelectedItem?.value ?? null);\n    },\n  });\n\n  const { id: listboxId, ...listboxProps } = getMenuProps();\n\n  const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n    if (!event.currentTarget.contains(event.relatedTarget)) {\n      setFocused(false);\n    }\n  };\n\n  const onClear = () => {\n    selectItem(null);\n    onChange?.(null);\n  };\n\n  const showClearButton = clearable && inputValue.length > 0 && focused && !readonly && !disabled;\n  const resultsFound = items.length > 0;\n  const showInlineMessage = description && !isOpen && !invalid;\n  const showErrorMessage = invalid && message && !isOpen;\n\n  // Calculate aria-describedby\n  const inputDescribedBy = useMemo(() => {\n    const ids: string[] = [];\n    if (description) ids.push(`${id}-description`);\n    if (message) ids.push(`${id}-message`);\n    return ids.length > 0 ? ids.join(' ') : undefined;\n  }, [id, description, message]);\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>\n            {label}\n            {required ? ' (required)' : ''}\n          </Label>\n          <UtilityFragment vFlexRow>\n            <InputContainer\n              onBlur={handleBlur}\n              onFocus={() => {\n                setFocused(true);\n              }}\n            >\n              {leadingIcon}\n              <Input\n                aria-describedby={inputDescribedBy}\n                aria-haspopup=\"listbox\"\n                aria-invalid={invalid}\n                disabled={disabled}\n                name={`${id}-input`}\n                type=\"text\"\n                {...getInputProps({\n                  'aria-expanded': isOpen,\n                  'aria-owns': listboxId,\n                  ...(filterable && { 'aria-autocomplete': 'list' as const }),\n                  ...(readonly && { readOnly: true }),\n                })}\n                {...remainingProps}\n              />\n              {showClearButton && (\n                <Button\n                  aria-label=\"clear\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={onClear}\n                  subtle\n                >\n                  <VisaClearAltTiny />\n                </Button>\n              )}\n              {!hideToggleButton && (\n                <Button\n                  aria-label=\"expand\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  disabled={readonly || disabled}\n                  {...getToggleButtonProps()}\n                >\n                  {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                </Button>\n              )}\n            </InputContainer>\n          </UtilityFragment>\n          {showInlineMessage && <InputMessage id={`${id}-description`}>{description}</InputMessage>}\n          {showErrorMessage && (\n            <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\">\n              <VisaErrorTiny />\n              {message}\n            </InputMessage>\n          )}\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <Listbox id={listboxId} {...listboxProps}>\n          {resultsFound ? (\n            items.map((item, index) => (\n              <ListboxItem\n                key={`${id}-item-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  index,\n                  item,\n                  'aria-selected': selectedItem?.value === item.value,\n                  'aria-disabled': item.disabled,\n                })}\n              >\n                <UtilityFragment vFlexShrink0>\n                  <Radio tag=\"span\" />\n                </UtilityFragment>\n                {item.label}\n              </ListboxItem>\n            ))\n          ) : (\n            <UtilityFragment vFlex vJustifyContent=\"center\" vPaddingVertical={8}>\n              <li>\n                <Typography variant=\"label-large\">No results found.</Typography>\n              </li>\n            </UtilityFragment>\n          )}\n        </Listbox>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n\n// export default NovaCombobox;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  autoSelect: boolean;\n  clearable: boolean;\n  description: string;\n  disabled: boolean;\n  filterable: boolean;\n  hideToggleButton: boolean;\n  invalid: boolean;\n  label: string;\n  leadingIcon: boolean;\n  message: string;\n  options: string;\n  readonly: boolean;\n  required: boolean;\n}\n\nconst demoOptions: ComboboxOption[] = [\n  { label: 'Option A', value: 'option-a' },\n  { label: 'Option B', value: 'option-b' },\n  { label: 'Option C', value: 'option-c', disabled: true },\n  { label: 'Option D', value: 'option-d' },\n  { label: 'Option E', value: 'option-e' },\n];\n\n// Demo Component\nexport const NovaComboboxDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    autoSelect: false,\n    clearable: false,\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    filterable: false,\n    hideToggleButton: false,\n    invalid: false,\n    label: 'Label',\n    leadingIcon: false,\n    message: 'This is required text that describes the error in more detail.',\n    options: JSON.stringify(demoOptions, null, 2),\n    readonly: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'options'> & { options: ComboboxOption[] }\n  >({\n    ...defaultCustomizations,\n    options: demoOptions,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n  const [selectedValue, setSelectedValue] = useState<string | null>(null);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.options || '[]') as ComboboxOption[];\n      setCustomizations({\n        ...formValues,\n        options: parsedOptions,\n      });\n    } catch (error) {\n      console.error('Invalid JSON:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      options: demoOptions,\n    });\n    setSelectedValue(null);\n  };\n\n  return (\n    <div>\n      <NovaCombobox\n        autoSelect={customizations.autoSelect}\n        clearable={customizations.clearable}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        filterable={customizations.filterable}\n        hideToggleButton={customizations.hideToggleButton}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        leadingIcon={customizations.leadingIcon ? <VisaSearchLow /> : undefined}\n        message={customizations.invalid ? customizations.message : undefined}\n        onChange={setSelectedValue}\n        options={customizations.options}\n        readonly={customizations.readonly}\n        required={customizations.required}\n        value={selectedValue}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <Typography variant=\"body-2\" tag=\"p\">\n          Selected value: {selectedValue || 'None'}\n        </Typography>\n      </div>\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Error message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              <NovaInput<'textarea'>\n                fixed={false}\n                label=\"Options (JSON)\"\n                onChange={e => handleInputChange('options', e.target.value)}\n                style={{ blockSize: '150px' }}\n                textarea\n                value={formValues.options}\n              />\n\n              <NovaCheckbox\n                checked={formValues.autoSelect}\n                label=\"Auto select (with filterable)\"\n                onChange={e => handleInputChange('autoSelect', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.clearable}\n                label=\"Clearable\"\n                onChange={e => handleInputChange('clearable', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.disabled}\n                label=\"Disabled\"\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.filterable}\n                label=\"Filterable\"\n                onChange={e => handleInputChange('filterable', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.hideToggleButton}\n                label=\"Hide toggle button\"\n                onChange={e => handleInputChange('hideToggleButton', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.invalid}\n                label=\"Invalid\"\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.leadingIcon}\n                label=\"Leading icon\"\n                onChange={e => handleInputChange('leadingIcon', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.readonly}\n                label=\"Readonly\"\n                onChange={e => handleInputChange('readonly', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.required}\n                label=\"Required\"\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaComboboxDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable combobox"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Combobox",
          "selector": "<Combobox />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Dropdown menu enabling users to enter text or select items from a list."
        },
        {
          "order": 2,
          "name": "Dropdownmenu",
          "selector": "<DropdownMenu />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive element enabling users to select a single option from a list."
        },
        {
          "order": 3,
          "name": "dropdown-menu",
          "type": "related",
          "selector": "<DropdownMenu />",
          "description": ""
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Combobox",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of the component"
          }
        },
        {
          "name": "tag",
          "section": "Dropdownmenu",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Scroll"
          }
        }
      ]
    },
    {
      "name": "content-card",
      "version": "0.0.1",
      "description": "Compact displays summarizing or directing users to more information.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default content cards",
          "description": "",
          "order": 1
        },
        {
          "name": "Dashboard content cards",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/default-content-card",
            "github": "apps/workshop/src/examples/components/content-card/default-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  ContentCard,\n  ContentCardBody,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Link,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nexport const DefaultContentCard = () => {\n  return (\n    <ContentCard>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n        <ContentCardSubtitle variant=\"subtitle-3\">Subtitle</ContentCardSubtitle>\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={16} vPaddingTop={12}>\n          <Button>Primary action</Button>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Default content card"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/with-buttons-content-card",
            "github": "apps/workshop/src/examples/components/content-card/with-buttons-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny, VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  ContentCard,\n  ContentCardBody,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Link,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nexport const WithButtonsContentCard = () => {\n  return (\n    <ContentCard>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <Utility vAlignItems=\"center\" vFlex vFlexRow vJustifyContent=\"between\">\n          <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n          <Button aria-label=\"Export [Headline]\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaFileUploadTiny />\n          </Button>\n        </Utility>\n        <ContentCardSubtitle variant=\"subtitle-3\">Subtitle</ContentCardSubtitle>\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={16} vPaddingTop={12}>\n          <Button>Primary action</Button>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Content card with UI buttons"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/clickable-content-card",
            "github": "apps/workshop/src/examples/components/content-card/clickable-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  ContentCard,\n  ContentCardBody,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nexport const ClickableContentCard = () => {\n  return (\n    <ContentCard clickable tag=\"button\">\n      <Utility element={<ContentCardBody tag=\"span\" />} vAlignItems=\"start\" vFlex vFlexCol vGap={4}>\n        <ContentCardTitle variant=\"headline-4\" tag=\"span\">\n          Headline\n          <VisaChevronRightTiny rtl className=\"v-icon-move\" />\n        </ContentCardTitle>\n        <ContentCardSubtitle variant=\"subtitle-3\" tag=\"span\">\n          Subtitle\n        </ContentCardSubtitle>\n        <Utility element={<Typography tag=\"span\" />} vPaddingTop={4}>\n          This is optional text that describes the headline in more detail.\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Clickable content card"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/clickable-disabled-content-card",
            "github": "apps/workshop/src/examples/components/content-card/clickable-disabled-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaSecurityLockTiny } from '@visa/nova-icons-react';\nimport {\n  ContentCard,\n  ContentCardBody,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nexport const ClickableDisabledContentCard = () => {\n  return (\n    <ContentCard aria-disabled=\"true\" clickable tag=\"button\">\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <Utility vAlignItems=\"center\" vFlex vGap={12}>\n          <ContentCardTitle variant=\"headline-4\" tag=\"span\">\n            Headline\n          </ContentCardTitle>\n          <VisaSecurityLockTiny />\n        </Utility>\n        <ContentCardSubtitle variant=\"subtitle-3\" tag=\"span\">\n          Subtitle\n        </ContentCardSubtitle>\n        <Typography className=\"v-pt-4\" tag=\"span\">\n          This is optional text that describes the headline in more detail.\n        </Typography>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Disabled clickable content card"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/compact-content-card",
            "github": "apps/workshop/src/examples/components/content-card/compact-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { ContentCard, ContentCardBody, ContentCardSubtitle, ContentCardTitle, Link, Utility } from '@visa/nova-react';\n\nexport const CompactContentCard = () => {\n  return (\n    <ContentCard borderBlockEnd>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={10}>\n        <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n        <ContentCardSubtitle className=\"v-pt-4\" variant=\"body-2\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </ContentCardSubtitle>\n        <Utility vPaddingTop={12}>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Compact content card"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/category-content-card",
            "github": "apps/workshop/src/examples/components/content-card/category-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountLow, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  ContentCard,\n  ContentCardBody,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Link,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\nexport const CategoryContentCard = () => {\n  return (\n    <ContentCard>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <Utility vAlignItems=\"center\" vFlex vGap={6} vPaddingBottom={8}>\n          <VisaAccountLow />\n          <Typography style={{ color: 'var(--palette-default-active)' }} variant=\"overline\" tag=\"h3\">\n            Category\n          </Typography>\n        </Utility>\n        <ContentCardTitle variant=\"headline-4\" tag=\"h4\">\n          Headline\n        </ContentCardTitle>\n        <ContentCardSubtitle variant=\"subtitle-3\" tag=\"h5\">\n          Subtitle\n        </ContentCardSubtitle>\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vAlignItems=\"center\" vFlex vGap={16} vPaddingTop={12}>\n          <Button>Primary action</Button>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Content card with category"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/icon-content-card",
            "github": "apps/workshop/src/examples/components/content-card/icon-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny, VisaSecurityLockHigh } from '@visa/nova-icons-react';\nimport { ContentCard, ContentCardBody, ContentCardTitle, Divider, Link, Typography, Utility } from '@visa/nova-react';\n\nexport const IconContentCard = () => {\n  return (\n    <ContentCard>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <Utility element={<VisaSecurityLockHigh />} vPaddingBottom={12} />\n        <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n        <Divider />\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vPaddingTop={12}>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Content card with icon"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Default content cards",
          "url": {
            "iframe": "components/content-card/image-header-content-card",
            "github": "apps/workshop/src/examples/components/content-card/image-header-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  ContentCard,\n  ContentCardBody,\n  ContentCardImage,\n  ContentCardSubtitle,\n  ContentCardTitle,\n  Link,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\n\nexport const ImageHeaderContentCard = () => {\n  return (\n    <ContentCard style={{ inlineSize: '50vw' }}>\n      <ContentCardImage<'img'>\n        // If your image is NOT decorative, be sure to write alt text describing the image\n        alt=\"\"\n        // Make sure the src path is correct for your image\n        src={BASE_URL + '/content-card-image.png'}\n        style={{ blockSize: 'auto', inlineSize: '100%', objectFit: 'contain', overflow: 'hidden' }}\n        tag=\"img\"\n      />\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n        <ContentCardSubtitle variant=\"subtitle-3\">Subtitle</ContentCardSubtitle>\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={16} vPaddingTop={12}>\n          <Button>Primary action</Button>\n          <Link href=\"./content-card\" noUnderline>\n            Destination label <VisaChevronRightTiny rtl />\n          </Link>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Content card with image"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Dashboard content cards",
          "url": {
            "iframe": "components/content-card/compact-dashboard-content-card",
            "github": "apps/workshop/src/examples/components/content-card/compact-dashboard-content-card.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaArrowUpTiny } from '@visa/nova-icons-react';\nimport { ContentCard, ContentCardBody, ContentCardTitle, Typography, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'compact-dashboard-content-card';\n\nexport const CompactDashboardContentCard = () => {\n  return (\n    <ContentCard>\n      <Utility element={<ContentCardBody />} vFlex vFlexCol vGap={4}>\n        <Utility vAlignItems=\"center\" vFlex vFlexRow vJustifyContent=\"between\">\n          <ContentCardTitle variant=\"headline-4\">Headline</ContentCardTitle>\n        </Utility>\n        <Typography className=\"v-pt-4\">\n          This is optional text that describes the headline and subtitle in more detail.\n        </Typography>\n        <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={16} vPaddingTop={12}>\n          <Typography style={{ color: 'var(--palette-messaging-text-positive)' } as CSSProperties} variant=\"display-2\">\n            0,000\n          </Typography>\n          <Utility vAlignContent=\"end\" vAlignItems=\"center\" vFlex vFlexCol vGap={4} vMarginTop={8}>\n            <VisaArrowUpTiny\n              aria-hidden=\"false\"\n              title=\"Increasing value\"\n              titleId={`${id}-trend-title`}\n              aria-labelledby={`${id}-trend-title ${id}-trend-label`}\n            />\n            <Typography id={`${id}-trend-label`} aria-hidden=\"true\">\n              Label\n            </Typography>\n          </Utility>\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n"
          },
          "name": "Compact dashboard content card"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Contentcard",
          "selector": "<ContentCard />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Compact displays summarizing or directing users to more information."
        },
        {
          "order": 2,
          "name": "Contentcardbody",
          "selector": "<ContentCardBody />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Element containing the body elements of the content card."
        },
        {
          "order": 3,
          "name": "Contentcardimage",
          "selector": "<ContentCardImage />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Hero image for content card."
        },
        {
          "order": 4,
          "name": "Contentcardsubtitle",
          "selector": "<ContentCardSubtitle />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Subtitle component for content card. Extends typography component."
        },
        {
          "order": 5,
          "name": "Contentcardtitle",
          "selector": "<ContentCardTitle />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Title component for content card. Extends typography component."
        }
      ],
      "properties": [
        {
          "name": "borderBlockEnd",
          "section": "Contentcard",
          "data": {
            "name": "borderBlockEnd",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Show bottom border on content card"
          }
        },
        {
          "name": "clickable",
          "section": "Contentcard",
          "data": {
            "name": "clickable",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Card Clickable"
          }
        },
        {
          "name": "tag",
          "section": "Contentcard",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Contentcardbody",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Contentcardimage",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "colorScheme",
          "section": "Contentcardsubtitle",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Contentcardsubtitle",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "h4",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Contentcardsubtitle",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        },
        {
          "name": "colorScheme",
          "section": "Contentcardtitle",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Contentcardtitle",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "h3",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Contentcardtitle",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "date-and-time-selectors",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Date selectors",
          "description": "",
          "order": 1
        },
        {
          "name": "Date Range Selectors",
          "description": "",
          "order": 2
        },
        {
          "name": "Time selectors",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Date selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/default-date-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/default-date-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-date-selector';\n\nexport const DefaultDateSelector = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input id={id} required type=\"date\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default date selector"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Date selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/read-only-date-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/read-only-date-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'read-only-date-selector';\n\nexport const ReadOnlyDateSelector = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input id={id} required type=\"date\" readOnly />\n      </InputContainer>\n    </Utility>\n  );\n};"
          },
          "name": "Read-only date selector"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Date selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/disabled-date-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/disabled-date-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-date-selector';\n\nexport const DisabledDateSelector = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input id={id} required type=\"date\" disabled />\n      </InputContainer>\n    </Utility>\n  );\n};"
          },
          "name": "Disabled date selector"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Date selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/date-selector-with-error",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/date-selector-with-error.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\nimport { Button, Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'date-selector-with-error';\n\nexport const DateSelectorWithError = () => {\n  const [errorState, setErrorState] = useState(false);\n\n  return (\n    <>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Input id={id} required type=\"date\" aria-invalid={errorState} />\n        </InputContainer>\n        {errorState && (\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\">\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </Utility>\n      <Utility vFlex vGap={12} vMarginTop={16}>\n        <Button id={`${id}-submit-button`} onClick={() => setErrorState(true)}>\n          Submit\n        </Button>\n        <Button id={`${id}-reset-button`} colorScheme=\"secondary\" onClick={() => setErrorState(false)}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Date selector with error"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Date selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/min-max-date-input",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/min-max-date-input.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'min-max-date';\n\nexport const MinMaxDateInput = () => {\n  return (\n    <Utility vFlex vFlexWrap vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input id={id} max=\"1999-06-29\" min=\"1999-01-27\" required type=\"date\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Date selector with disabled dates"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Date Range Selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/default-date-range-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/default-date-range-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-date-range-selector';\n\nexport const DefaultDateRangeSelector = () => {\n  const [endDate, setEndDate] = useState('');\n  const [startDate, setStartDate] = useState('');\n\n  const onDateChange = (event: FormEvent<HTMLInputElement>, isStartDate: boolean) => {\n    const { value } = event.currentTarget;\n    isStartDate ? setStartDate(value) : setEndDate(value);\n  };\n\n  return (\n    <Utility vFlex vFlexWrap vGap=\"12\">\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-start-date`}>Start Date Label (required)</Label>\n        <InputContainer>\n          <Input\n            id={`${id}-start-date`}\n            max={endDate ? endDate : undefined}\n            onChange={event => onDateChange(event, true)}\n            required\n            type=\"date\"\n          />\n        </InputContainer>\n      </Utility>\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-end-date`}>End Date Label (required)</Label>\n        <InputContainer>\n          <Input\n            id={`${id}-end-date`}\n            min={startDate ? startDate : undefined}\n            onChange={event => onDateChange(event, false)}\n            required\n            type=\"date\"\n          />\n        </InputContainer>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default date range selector"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Date Range Selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/stacked-date-range-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/stacked-date-range-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'stacked-date-range-selector';\n\nexport const StackedDateRangeSelector = () => {\n  const [endDate, setEndDate] = useState('');\n  const [startDate, setStartDate] = useState('');\n\n  const onDateChange = (event: FormEvent<HTMLInputElement>, isStartDate: boolean) => {\n    const { value } = event.currentTarget;\n    isStartDate ? setStartDate(value) : setEndDate(value);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"12\">\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-start-date`}>Start Date Label (required)</Label>\n        <InputContainer>\n          <Input\n            id={`${id}-start-date`}\n            max={endDate ? endDate : undefined}\n            onChange={event => onDateChange(event, true)}\n            required\n            type=\"date\"\n          />\n        </InputContainer>\n      </Utility>\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-end-date`}>End Date Label (required)</Label>\n        <InputContainer>\n          <Input\n            id={`${id}-end-date`}\n            min={startDate ? startDate : undefined}\n            onChange={event => onDateChange(event, false)}\n            required\n            type=\"date\"\n          />\n        </InputContainer>\n      </Utility>\n    </Utility>\n  );\n};"
          },
          "name": "Stacked date range selector"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Time selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/default-time-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/default-time-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-time-selector';\n\nexport const DefaultTimeSelector = () => {\n  return (\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-time`}>Label (required)</Label>\n        <InputContainer>\n          <Input id={`${id}-time`} required type=\"time\" />\n        </InputContainer>\n      </Utility>\n  );\n};\n"
          },
          "name": "Default time selector"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Time selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/read-only-time-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/read-only-time-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'read-only-time-selector';\n\nexport const ReadOnlyTimeSelector = () => {\n  return (\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-time`}>Label (required)</Label>\n        <InputContainer>\n          <Input id={`${id}-time`} required type=\"time\" readOnly/>\n        </InputContainer>\n      </Utility>\n  );\n};\n"
          },
          "name": "Read-only time selector"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Time selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/disabled-time-selector",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/disabled-time-selector.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-time-selector';\n\nexport const DisabledTimeSelector = () => {\n  return (\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-time`}>Label (required)</Label>\n        <InputContainer>\n          <Input id={`${id}-time`} required type=\"time\" disabled/>\n        </InputContainer>\n      </Utility>\n  );\n};\n"
          },
          "name": "Disabled time selector"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Time selectors",
          "url": {
            "iframe": "components/date-and-time-selectors/time-selector-with-error",
            "github": "apps/workshop/src/examples/components/date-and-time-selectors/time-selector-with-error.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\nimport { Button, Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'time-selector-with-error';\n\nexport const TimeSelectorWithError = () => {\n  const [errorState, setErrorState] = useState(false);\n\n  return (\n    <>\n      <Utility vFlex vGap=\"4\" vFlexCol vFlexGrow>\n        <Label htmlFor={`${id}-time`}>Label (required)</Label>\n        <InputContainer>\n          <Input id={`${id}-time`} required type=\"time\" aria-invalid={errorState} />\n        </InputContainer>\n        {errorState && (\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\">\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </Utility>\n      <Utility vFlex vGap={12} vMarginTop={16}>\n        <Button id={`${id}-submit-button`} onClick={() => setErrorState(true)}>\n          Submit\n        </Button>\n        <Button id={`${id}-reset-button`} colorScheme=\"secondary\" onClick={() => setErrorState(false)}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Time selector with error"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "input",
          "type": "related",
          "selector": "<Input />",
          "description": ""
        }
      ],
      "properties": []
    },
    {
      "name": "dialog",
      "version": "0.0.1",
      "description": "Pop-up windows that overlay page content to facilitate user interactions or show important information.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default Dialogs",
          "description": "",
          "order": 1
        },
        {
          "name": "Custom dialog",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/default-dialog",
            "github": "apps/workshop/src/examples/components/dialog/default-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'dialog';\n\nexport const DefaultDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open default dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        id={id}\n        ref={ref}\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>Default title</DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n            <Button>Primary action</Button>\n            <Button colorScheme=\"secondary\">Secondary action</Button>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={() => ref.current?.close()}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Default dialog"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/error-dialog",
            "github": "apps/workshop/src/examples/components/dialog/error-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-dialog';\n\nexport const ErrorDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open error dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        id={id}\n        messageType=\"error\"\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n        ref={ref}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>\n            <MessageIcon messageType=\"error\" />\n            Error title\n          </DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n            <Button>Primary action</Button>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={() => ref.current?.close()}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Error dialog"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/success-dialog",
            "github": "apps/workshop/src/examples/components/dialog/success-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'success-dialog';\n\nexport const SuccessDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open success dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        ref={ref}\n        id={id}\n        messageType=\"success\"\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>\n            <MessageIcon messageType=\"success\" />\n            Success title\n          </DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n            <Button>Primary action</Button>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={() => ref.current?.close()}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Success dialog"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/warning-dialog",
            "github": "apps/workshop/src/examples/components/dialog/warning-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'warning-dialog';\n\nexport const WarningDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open warning dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        ref={ref}\n        id={id}\n        messageType=\"warning\"\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>\n            <MessageIcon messageType=\"warning\" />\n            Warning title\n          </DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n            <Button>Primary action</Button>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={() => ref.current?.close()}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Warning dialog"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/close-button-dialog",
            "github": "apps/workshop/src/examples/components/dialog/close-button-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Button, Dialog, DialogContent, DialogHeader, Typography, useFocusTrap, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'no-close-dialog';\n\nexport const CloseButtonDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open dialog without close icon</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        ref={ref}\n        id={id}\n        messageType=\"error\"\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>\n            <MessageIcon messageType=\"error\" />\n            Error title\n          </DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vJustifyContent=\"end\" vPaddingTop={16}>\n            <Button onClick={() => ref.current?.close()}>Close</Button>\n          </Utility>\n        </DialogContent>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Dialog without close icon button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default Dialogs",
          "url": {
            "iframe": "components/dialog/touring-tips-dialog",
            "github": "apps/workshop/src/examples/components/dialog/touring-tips-dialog.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'touring-tips-dialog';\n\nexport const TouringTipsDialog = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  const onCloseDialog = () => ref.current?.close();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open touring tips dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        ref={ref}\n        id={id}\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>Touring tips title</DialogHeader>\n          <Utility vAlignItems=\"center\" vFlex vFlexRow vGap={8} vPaddingBottom={8}>\n            <svg width=\"36\" height=\"36\" viewBox=\"0 0 36 36\" fill=\"none\">\n              <rect width=\"36\" height=\"36\" rx=\"18\" fill=\"#B3D7FF\" fillOpacity=\"0.35\" />\n              <path\n                d=\"M17.238 13.856C16.8327 13.856 16.3953 13.936 15.926 14.096C15.4567 14.256 15.03 14.496 14.646 14.816H14.502L14.614 13.136C15.0087 12.88 15.478 12.6827 16.022 12.544C16.566 12.4053 17.0727 12.336 17.542 12.336C18.7473 12.336 19.6913 12.5867 20.374 13.088C21.0673 13.5787 21.414 14.4427 21.414 15.68C21.414 16.256 21.3233 16.784 21.142 17.264C20.9713 17.7333 20.742 18.16 20.454 18.544C20.1767 18.928 19.8833 19.28 19.574 19.6C19.382 19.8133 19.126 20.0747 18.806 20.384C18.486 20.6827 18.1287 21.008 17.734 21.36C17.3393 21.712 16.9393 22.0533 16.534 22.384H21.67L21.526 24H14.406V22.576C15.0247 22.0213 15.5527 21.5467 15.99 21.152C16.438 20.7573 16.8327 20.3947 17.174 20.064C17.5153 19.7333 17.83 19.4027 18.118 19.072C18.502 18.6347 18.8167 18.1493 19.062 17.616C19.318 17.072 19.446 16.5013 19.446 15.904C19.446 15.1467 19.2593 14.6187 18.886 14.32C18.5127 14.0107 17.9633 13.856 17.238 13.856Z\"\n                fill=\"black\"\n              />\n            </svg>\n            <Typography variant=\"body-2-bold\">Touring tips instructions</Typography>\n          </Utility>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vJustifyContent=\"between\" vPaddingTop={16}>\n            <Typography>2 of 4</Typography>\n            <Utility vFlex vFlexWrap vGap={8} vJustifyContent=\"between\">\n              <Button colorScheme=\"secondary\" onClick={onCloseDialog}>\n                Previous\n              </Button>\n              <Button onClick={onCloseDialog}>Next</Button>\n            </Utility>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={onCloseDialog}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": "Touring tips dialog"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Custom dialog",
          "url": {
            "iframe": "components/dialog/reusable",
            "github": "apps/workshop/src/examples/components/dialog/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  type DialogProperties,\n  type MessageType,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { type KeyboardEvent, type ReactNode, useEffect, useId, useRef, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Nova Dialog Component Props\nexport type NovaDialogProps = DialogProperties & {\n  actions?: ReactNode;\n  description?: string;\n  dismissible?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  onPrimaryButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n  onSecondaryButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n  open?: boolean;\n  primaryButtonLabel?: string;\n  secondaryButtonLabel?: string;\n  showIcon?: boolean;\n  title?: string;\n  titleContent?: ReactNode;\n};\n\n// Main Nova Dialog Component\nexport const NovaDialog = ({\n  actions,\n  children,\n  description,\n  dismissible = false,\n  id: idProp,\n  messageType,\n  onOpenChange,\n  onPrimaryButtonClick,\n  onSecondaryButtonClick,\n  open = false,\n  primaryButtonLabel,\n  secondaryButtonLabel,\n  showIcon = false,\n  title,\n  titleContent,\n  ...remainingProps\n}: NovaDialogProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n  const dialogRef = useRef<HTMLDialogElement>(null);\n\n  // Handle open/close state changes\n  useEffect(() => {\n    const dialog = dialogRef.current;\n    if (!dialog) return;\n    const dialogOpen = dialog.open;\n    if ((open && dialogOpen) || (!open && !dialogOpen)) return; // no change needed\n    if (open) {\n      dialog.showModal();\n    } else {\n      dialog.close();\n    }\n  }, [open]);\n\n  // Handle close\n  const handleClose = () => {\n    onOpenChange?.(false);\n  };\n\n  // Handle escape key\n  const handleEscapeKey = (event: KeyboardEvent<HTMLDialogElement>) => {\n    if (event.key !== 'Escape' || dismissible) return;\n    event.preventDefault();\n    handleClose();\n  };\n\n  return (\n    <Dialog\n      aria-describedby={description ? `${id}-description` : undefined}\n      aria-labelledby={`${id}-title`}\n      id={id}\n      ref={dialogRef}\n      onKeyDown={handleEscapeKey}\n      messageType={messageType}\n      {...remainingProps}\n    >\n      <DialogContent>\n        <DialogHeader id={`${id}-title`}>\n          {showIcon && <MessageIcon messageType={messageType as Parameters<typeof MessageIcon>[0]['messageType']} />}\n          {title}\n          {titleContent}\n        </DialogHeader>\n        {description && <Typography id={`${id}-description`}>{description}</Typography>}\n        {children}\n        <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n          {primaryButtonLabel && (\n            <Button autoFocus onClick={onPrimaryButtonClick}>\n              {primaryButtonLabel}\n            </Button>\n          )}\n          {secondaryButtonLabel && (\n            <Button colorScheme=\"secondary\" onClick={onSecondaryButtonClick}>\n              {secondaryButtonLabel}\n            </Button>\n          )}\n          {actions}\n        </Utility>\n      </DialogContent>\n\n      {dismissible && (\n        <DialogCloseButton onClick={handleClose}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      )}\n    </Dialog>\n  );\n};\n\n// export default NovaDialog;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  description: string;\n  dismissible: boolean;\n  messageType: MessageType;\n  primaryButtonLabel: string;\n  secondaryButtonLabel: string;\n  showIcon: boolean;\n  title: string;\n}\n\n// Demo Component\nexport const NovaDialogDemo = () => {\n  const [dialogOpen, setDialogOpen] = useState(false);\n\n  const messageTypes: { label: string; value: MessageType }[] = [\n    { label: 'Information', value: 'information' },\n    { label: 'Success', value: 'success' },\n    { label: 'Warning', value: 'warning' },\n    { label: 'Error', value: 'error' },\n    { label: 'Subtle', value: 'subtle' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    description: 'This is required text that describes the dialog title in more detail.',\n    dismissible: true,\n    messageType: 'information',\n    primaryButtonLabel: 'Primary action',\n    secondaryButtonLabel: 'Secondary action',\n    showIcon: true,\n    title: 'Nova title',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  const handlePrimaryClick = () => {\n    console.log('Dialog primary button clicked');\n  };\n\n  const handleSecondaryClick = () => {\n    console.log('Dialog secondary button clicked');\n  };\n\n  return (\n    <div>\n      <Button onClick={() => setDialogOpen(true)}>Open reusable dialog</Button>\n\n      <NovaDialog\n        description={customizations.description || ''}\n        dismissible={customizations.dismissible}\n        messageType={customizations.messageType}\n        onOpenChange={setDialogOpen}\n        onPrimaryButtonClick={handlePrimaryClick}\n        onSecondaryButtonClick={handleSecondaryClick}\n        open={dialogOpen}\n        primaryButtonLabel={customizations.primaryButtonLabel || ''}\n        secondaryButtonLabel={customizations.secondaryButtonLabel || ''}\n        showIcon={customizations.showIcon}\n        title={customizations.title || ''}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Primary button label\"\n                onChange={e => handleInputChange('primaryButtonLabel', e.target.value)}\n                value={formValues.primaryButtonLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Secondary button label\"\n                onChange={e => handleInputChange('secondaryButtonLabel', e.target.value)}\n                value={formValues.secondaryButtonLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Title\"\n                onChange={e => handleInputChange('title', e.target.value)}\n                value={formValues.title}\n              />\n\n              <NovaSelect\n                label=\"Message type\"\n                onChange={e => handleInputChange('messageType', e.target.value as MessageType)}\n                options={messageTypes}\n                value={formValues.messageType}\n              />\n\n              <NovaCheckbox\n                checked={formValues.dismissible}\n                label=\"Dismissible\"\n                onChange={e => handleInputChange('dismissible', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.showIcon}\n                label=\"Show icon\"\n                onChange={e => handleInputChange('showIcon', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaDialogDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable dialog"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Dialog",
          "selector": "<Dialog />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Pop-up windows that overlay page content to facilitate user interactions or show important information."
        },
        {
          "order": 2,
          "name": "DialogCloseButton",
          "selector": "<DialogCloseButton />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Button that appears in dialog pop-up windows to close them."
        },
        {
          "order": 3,
          "name": "Dialogheader",
          "selector": "<DialogHeader />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for the heading area of a dialog pop-up window."
        },
        {
          "order": 4,
          "name": "Messagecontent",
          "selector": "<MessageContent />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for message content elements."
        },
        {
          "order": 5,
          "name": "useFocusTrap",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to trap focus inside a container."
        }
      ],
      "properties": [
        {
          "name": "messageType",
          "section": "Dialog",
          "data": {
            "name": "messageType",
            "type": "\"subtle\" , \"warning\" , \"error\" , \"information\" , \"success\"",
            "default": "",
            "required": "false",
            "description": "Message Type"
          }
        },
        {
          "name": "tag",
          "section": "Dialog",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "dialog",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "DialogCloseButton",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "DialogCloseButton",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "children",
          "section": "DialogCloseButton",
          "data": {
            "name": "children",
            "type": "ReactNode",
            "default": "",
            "required": "false",
            "description": "@required"
          }
        },
        {
          "name": "colorScheme",
          "section": "DialogCloseButton",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "DialogCloseButton",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "DialogCloseButton",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "DialogCloseButton",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "DialogCloseButton",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "DialogCloseButton",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "DialogCloseButton",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "DialogCloseButton",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "colorScheme",
          "section": "Dialogheader",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Dialogheader",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "h2",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Dialogheader",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        },
        {
          "name": "tag",
          "section": "Messagecontent",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "divider",
      "version": "0.0.1",
      "description": "Visual element used to separate and group information on a page.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Examples",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/divider/default-divider",
            "github": "apps/workshop/src/examples/components/divider/default-divider.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Divider } from '@visa/nova-react';\n\nexport const DefaultDivider = () => {\n  return <Divider />;\n};\n"
          },
          "name": "Default divider"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/divider/section-divider",
            "github": "apps/workshop/src/examples/components/divider/section-divider.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Divider } from '@visa/nova-react';\n\nexport const SectionDivider = () => {\n  return <Divider dividerType=\"section\" />;\n};\n"
          },
          "name": "Section divider"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/divider/decorative-divider",
            "github": "apps/workshop/src/examples/components/divider/decorative-divider.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Divider } from '@visa/nova-react';\n\nexport const DecorativeDivider = () => {\n  return <Divider dividerType=\"decorative\" />;\n};\n"
          },
          "name": "Decorative divider"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Divider",
          "selector": "<Divider />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Visual element used to separate and group information on a page."
        }
      ],
      "properties": [
        {
          "name": "dividerType",
          "section": "Divider",
          "data": {
            "name": "dividerType",
            "type": "\"section\" , \"decorative\"",
            "default": "",
            "required": "false",
            "description": "Divider Type"
          }
        }
      ]
    },
    {
      "name": "dropdown-menu",
      "version": "0.0.1",
      "description": "Interactive element enabling users to select a single option from a list.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Text button dropdown menus",
          "description": "",
          "order": 1
        },
        {
          "name": "Icon button dropdown menus",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom dropdown menus",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Text button dropdown menus",
          "url": {
            "iframe": "components/dropdown-menu/default-dropdown-menu",
            "github": "apps/workshop/src/examples/components/dropdown-menu/default-dropdown-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport { VisaChevronDownTiny, VisaChevronUpTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\nimport { Button, DropdownButton, DropdownMenu, Listbox, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'dropdown-menu-default';\n\nexport const DefaultDropdownMenu = () => {\n  const [open, setOpen] = useState(false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-start',\n  });\n\n  const onClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick]);\n\n  return (\n    // This div is not required, it's used to show the whole dropdown menu in the example\n    <div style={{ blockSize: 250 }}>\n      <DropdownButton\n        aria-controls={id}\n        aria-expanded={open}\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        Action\n        {open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n      </DropdownButton>\n      {open && (\n        <DropdownMenu\n          id={id}\n          aria-hidden={!open}\n          ref={refs.setFloating}\n          style={{ inlineSize: '180px', ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vHide={!open}>\n            <Listbox>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 1\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 3\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 3\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\">\n                    Label 4\n                  </Button>\n                </UtilityFragment>\n              </li>\n            </Listbox>\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </div>\n  );\n};\n"
          },
          "name": "Default text button dropdown menu"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Icon button dropdown menus",
          "url": {
            "iframe": "components/dropdown-menu/icon-dropdown-menu",
            "github": "apps/workshop/src/examples/components/dropdown-menu/icon-dropdown-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport { VisaOptionHorizontalHigh } from '@visa/nova-icons-react';\nimport { useState } from 'react';\nimport { Button, DropdownButton, DropdownMenu, Listbox, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'dropdown-menu-icon';\n\nexport const IconDropdownMenu = () => {\n  const [open, setOpen] = useState(false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-start',\n  });\n\n  const onClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick]);\n\n  return (\n    // This div is not required, it's used to show the whole dropdown menu in the example\n    <div style={{ blockSize: 250 }}>\n      <DropdownButton\n        aria-controls={id}\n        aria-expanded={open}\n        aria-label=\"see more options\"\n        iconButton\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        <VisaOptionHorizontalHigh />\n      </DropdownButton>\n      {open && (\n        <DropdownMenu\n          id={id}\n          aria-hidden={!open}\n          ref={refs.setFloating}\n          style={{ inlineSize: '180px', ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vHide={!open}>\n            <Listbox>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 1\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 2\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 2\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 4\n                  </Button>\n                </UtilityFragment>\n              </li>\n            </Listbox>\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </div>\n  );\n};\n"
          },
          "name": "Default icon button dropdown menu"
        },
        {
          "description": "Custom dropdown menu with tabs.",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Custom dropdown menus",
          "url": {
            "iframe": "components/dropdown-menu/dropdown-menu-with-tabs",
            "github": "apps/workshop/src/examples/components/dropdown-menu/dropdown-menu-with-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport { VisaOptionHorizontalHigh } from '@visa/nova-icons-react';\nimport { Button, DropdownButton, DropdownMenu, Tab, Tabs, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'dropdown-menu-with-tabs';\n\nexport const DropdownMenuWithTabs = () => {\n  const [open, setOpen] = useState(false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-start',\n  });\n\n  const onClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick]);\n\n  return (\n    // This div is not required, it's used to show the whole dropdown menu in the example\n    <div style={{ blockSize: 250 }}>\n      <DropdownButton\n        aria-controls={id}\n        aria-expanded={open}\n        aria-label=\"see more options\"\n        iconButton\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        <VisaOptionHorizontalHigh />\n      </DropdownButton>\n      {open && (\n        <DropdownMenu\n          id={id}\n          ref={refs.setFloating}\n          style={{ inlineSize: 'max-content', ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vGap={4} vPaddingVertical={7} vPaddingRight={8} vHide={!open}>\n            <Tabs orientation=\"vertical\" role=\"tablist\">\n              <Tab role=\"none\">\n                <Button aria-selected=\"false\" colorScheme=\"tertiary\" role=\"tab\">\n                  Label 1\n                </Button>\n              </Tab>\n              <Tab role=\"none\">\n                <Button aria-selected=\"true\" colorScheme=\"tertiary\" role=\"tab\">\n                  Label 2\n                </Button>\n              </Tab>\n              <Tab role=\"none\">\n                <Button aria-selected=\"false\" colorScheme=\"tertiary\" role=\"tab\">\n                  Label 3\n                </Button>\n              </Tab>\n              <Tab role=\"none\">\n                <Button aria-selected=\"false\" colorScheme=\"tertiary\" role=\"tab\">\n                  Label 4\n                </Button>\n              </Tab>\n            </Tabs>\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </div>\n  );\n};\n"
          },
          "name": "Dropdown menu with tabs"
        },
        {
          "description": "Custom dropdown menu with leading icons and destructive action.",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Custom dropdown menus",
          "url": {
            "iframe": "components/dropdown-menu/dropdown-menu-with-leading-icons",
            "github": "apps/workshop/src/examples/components/dropdown-menu/dropdown-menu-with-leading-icons.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport {\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaDeleteTiny,\n  VisaExportTiny,\n  VisaFileDownloadTiny,\n} from '@visa/nova-icons-react';\nimport { Button, DropdownButton, DropdownMenu, Listbox, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'dropdown-menu-with-leading-icons';\n\nexport const DropdownMenuWithLeadingIcons = () => {\n  const [open, setOpen] = useState(false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-start',\n  });\n\n  const onClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick]);\n\n  return (\n    // This div is not required, it's used to show the whole dropdown menu in the example\n    <div style={{ blockSize: 250 }}>\n      <DropdownButton\n        aria-controls={id}\n        aria-expanded={open}\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        Action\n        {open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n      </DropdownButton>\n      {open && (\n        <DropdownMenu\n          id={id}\n          aria-hidden={!open}\n          ref={refs.setFloating}\n          style={{ inlineSize: '180px', ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vHide={!open}>\n            <Listbox>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    <VisaExportTiny /> Label 1\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    <VisaFileDownloadTiny /> Label 2\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    <VisaFileDownloadTiny /> Label 3\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" destructive>\n                    <VisaDeleteTiny /> Label 4\n                  </Button>\n                </UtilityFragment>\n              </li>\n            </Listbox>\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </div>\n  );\n};\n"
          },
          "name": "Dropdown menu with leading icons and destructive action"
        },
        {
          "description": "A reusable dropdown menu component that can be easily customized and integrated into various parts of your application.",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Custom dropdown menus",
          "url": {
            "iframe": "components/dropdown-menu/reusable",
            "github": "apps/workshop/src/examples/components/dropdown-menu/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { offset, useClick, useDismiss, useFloating, useInteractions, type Placement } from '@floating-ui/react';\nimport {\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaDeleteTiny,\n  VisaExportTiny,\n  VisaFileDownloadTiny,\n  VisaFileUploadTiny,\n  VisaOptionHorizontalHigh,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  DropdownButton,\n  DropdownMenu,\n  Listbox,\n  Tab,\n  Tabs,\n  useModel,\n  Utility,\n  UtilityFragment,\n  type ButtonProperties,\n  type UtilityFragmentProperties,\n} from '@visa/nova-react';\nimport {\n  cloneElement,\n  isValidElement,\n  useId,\n  useState,\n  type FormEvent,\n  type MouseEvent,\n  type ReactElement,\n  type ReactNode,\n} from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Props passed to the trigger element\nexport type DropdownTriggerProps = {\n  ref: (node: HTMLElement | null) => void;\n} & Record<string, unknown>;\n\nexport type NovaDropdownMenuOption = Omit<ButtonProperties, 'children'> & {\n  label?: ReactNode;\n  render?: (item: Omit<NovaDropdownMenuOption, 'render'>) => ReactNode;\n  prefix?: ReactNode;\n  selected?: boolean;\n  suffix?: ReactNode;\n  vJustifyContent?: UtilityFragmentProperties['vJustifyContent'];\n};\n\n// Nova DropdownMenu Component Props\nexport type NovaDropdownMenuProps = ButtonProperties & {\n  element?: ReactElement | ((props: DropdownTriggerProps) => ReactNode);\n  maxWidth?: CSSStyleDeclaration['maxInlineSize'];\n  offset?: number;\n  onOpenChange?: (open: boolean) => void;\n  open?: boolean;\n  options?: NovaDropdownMenuOption[];\n  optionRender?: NovaDropdownMenuOption['render'];\n  placement?: Placement;\n  showToggleIcon?: boolean;\n};\n\n// Main Nova DropdownMenu Component\nexport const NovaDropdownMenu = ({\n  children,\n  element,\n  id: idProp,\n  maxWidth = 'unset',\n  offset: offsetValue = 0,\n  onOpenChange,\n  open: openProp,\n  options = [],\n  optionRender,\n  placement = 'bottom-start',\n  showToggleIcon = true,\n  ...remainingProps\n}: NovaDropdownMenuProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n  const [open, setOpen] = useModel(openProp, onOpenChange, false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    middleware: [offset(offsetValue)],\n    open,\n    onOpenChange: setOpen,\n    placement,\n  });\n\n  const onClick = useClick(context);\n  const onDismiss = useDismiss(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick, onDismiss]);\n\n  // Props to pass to the trigger element\n  const triggerProps: DropdownTriggerProps = {\n    ref: refs.setReference,\n    ...getReferenceProps(),\n  };\n\n  const hasSelectedOption = options.some(option => option.selected);\n\n  const optionsRendered = options.map((option, index) => {\n    const {\n      label,\n      onClick: onItemClick,\n      prefix,\n      render,\n      selected,\n      suffix,\n      vJustifyContent,\n      ...remainingButtonProps\n    } = option;\n    const onClick = (e: MouseEvent<HTMLButtonElement>) => {\n      onItemClick?.(e);\n      setOpen(false);\n    };\n    const buttonProps = {\n      ...remainingButtonProps,\n      'aria-selected': selected && hasSelectedOption ? 'true' : undefined,\n      className: 'v-listbox-item',\n      onClick: onClick,\n      role: 'tab',\n    };\n    const renderedProps = { ...buttonProps, ...option } as NovaDropdownMenuOption;\n    delete renderedProps.render; // Remove render from props passed to optionRender\n    return (\n      <UtilityFragment key={id + '-option-' + index} vPaddingBottom={2}>\n        <Tab role=\"none\">\n          {optionRender ? (\n            optionRender(renderedProps)\n          ) : render ? (\n            render(renderedProps)\n          ) : (\n            <UtilityFragment vJustifyContent={vJustifyContent}>\n              <Button colorScheme=\"tertiary\" subtle {...(buttonProps as ButtonProperties)}>\n                {prefix}\n                {label}\n                {suffix}\n              </Button>\n            </UtilityFragment>\n          )}\n        </Tab>\n      </UtilityFragment>\n    );\n  });\n\n  return (\n    <>\n      {element && (\n        <>\n          {typeof element === 'function' && element(triggerProps)}\n          {isValidElement(element) && cloneElement(element, triggerProps)}\n        </>\n      )}\n\n      {!element && (\n        <DropdownButton\n          aria-controls={id}\n          aria-expanded={open}\n          id={`${id}-button`}\n          {...remainingProps}\n          {...triggerProps}\n        >\n          {children}\n          {showToggleIcon && (open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />)}\n        </DropdownButton>\n      )}\n      {open && (\n        <DropdownMenu\n          id={id}\n          aria-hidden={!open}\n          ref={refs.setFloating}\n          style={{ inlineSize: 'max-content', maxInlineSize: maxWidth, zIndex: 10, ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vPaddingVertical={4} vPaddingRight={4} vHide={!open}>\n            {hasSelectedOption ? (\n              <Tabs orientation=\"vertical\" role=\"tablist\">\n                {optionsRendered}\n              </Tabs>\n            ) : (\n              <Listbox>{optionsRendered}</Listbox>\n            )}\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </>\n  );\n};\n\n// export default NovaDropdownMenu;\n\n/** !!! DELETE ME START !!! */\n\nconst demoOptions: NovaDropdownMenuOption[] = [\n  { disabled: true, label: 'Label 1' },\n  { label: 'Label 2', selected: true },\n  { label: 'Label 3' },\n  { label: 'Label 4' },\n];\n\n// These are separate from the main options because these can't be customized inside of a textarea input.\nconst demoOptionsIcons: ReactNode[] = [\n  // eslint-disable-next-line react/jsx-key\n  <VisaExportTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaFileDownloadTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaFileUploadTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaDeleteTiny />,\n];\n\nconst buttonColors: { label: string; value: ButtonProperties['colorScheme'] }[] = [\n  { label: 'Primary', value: 'primary' },\n  { label: 'Secondary', value: 'secondary' },\n  { label: 'Tertiary', value: 'tertiary' },\n];\n\nconst buttonSizes: { label: string; value: ButtonProperties['buttonSize'] }[] = [\n  { label: 'Small', value: 'small' },\n  { label: 'Medium', value: 'medium' },\n  { label: 'Large', value: 'large' },\n];\n\nconst placements: { label: string; value: Placement }[] = [\n  { label: 'Bottom', value: 'bottom' },\n  { label: 'Bottom end', value: 'bottom-end' },\n  { label: 'Bottom start', value: 'bottom-start' },\n  { label: 'Left', value: 'left' },\n  { label: 'Left end', value: 'left-end' },\n  { label: 'Left start', value: 'left-start' },\n  { label: 'Right', value: 'right' },\n  { label: 'Right end', value: 'right-end' },\n  { label: 'Right start', value: 'right-start' },\n  { label: 'Top', value: 'top' },\n  { label: 'Top start', value: 'top-start' },\n  { label: 'Top end', value: 'top-end' },\n];\n\n// Demo Component Types\ninterface DemoCustomizations {\n  buttonSize: ButtonProperties['buttonSize'];\n  colorScheme: ButtonProperties['colorScheme'];\n  iconButton: boolean;\n  options: string;\n  label: string;\n  maxWidth: string;\n  offset: number;\n  placement: Placement;\n  showPrefixIcons: boolean;\n  showSuffixIcons: boolean;\n  showToggleIcon: boolean;\n}\n\nconst defaultCustomizations: DemoCustomizations = {\n  buttonSize: 'medium',\n  colorScheme: 'primary',\n  iconButton: false,\n  label: 'Action',\n  maxWidth: 'unset',\n  offset: 0,\n  options: JSON.stringify(demoOptions, null, 4),\n  placement: 'bottom-start',\n  showPrefixIcons: true,\n  showSuffixIcons: false,\n  showToggleIcon: true,\n};\n\n// Demo Component\nexport const NovaDropdownMenuDemo = () => {\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'options'> & { options: NovaDropdownMenuOption[] }\n  >({\n    ...defaultCustomizations,\n    options: demoOptions,\n  });\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.options || '[]') as NovaDropdownMenuOption[];\n      setCustomizations({\n        ...formValues,\n        options: parsedOptions,\n      });\n    } catch (error) {\n      console.error('Invalid JSON for options:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      options: demoOptions,\n    });\n  };\n  const handleClick = () => {\n    console.log('DropdownMenu button clicked');\n  };\n\n  const optionsWithCustomizations = customizations.options.map((option, index) => {\n    const prefix = customizations.showPrefixIcons ? demoOptionsIcons[index % demoOptionsIcons.length] : undefined;\n    const suffix = customizations.showSuffixIcons ? demoOptionsIcons[index % demoOptionsIcons.length] : undefined;\n    const vJustifyContent = customizations.showSuffixIcons ? 'between' : undefined;\n    const style = customizations.showSuffixIcons ? { minWidth: '150px' } : undefined;\n    return { ...option, prefix, suffix, vJustifyContent, style } as NovaDropdownMenuOption;\n  });\n\n  return (\n    <div>\n      <NovaDropdownMenu\n        aria-label={customizations.iconButton ? customizations.label : undefined}\n        buttonSize={customizations.buttonSize || undefined}\n        colorScheme={customizations.colorScheme || undefined}\n        iconButton={customizations.iconButton || undefined}\n        onClick={handleClick}\n        options={optionsWithCustomizations || []}\n        offset={+customizations.offset}\n        placement={customizations.placement || 'top'}\n        maxWidth={customizations.maxWidth || 'unset'}\n        showToggleIcon={customizations.showToggleIcon}\n      >\n        {customizations.iconButton ? <VisaOptionHorizontalHigh /> : customizations.label || ''}\n      </NovaDropdownMenu>\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                placeholder=\"Primary action\"\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                blockSize=\"100px\"\n                label=\"Menu options (JSON)\"\n                onChange={e => handleInputChange('options', e.target.value)}\n                resizable\n                textarea\n                value={formValues.options}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Max width\"\n                onChange={e => handleInputChange('maxWidth', e.target.value)}\n                placeholder=\"100px\"\n                value={formValues.maxWidth}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Offset\"\n                onChange={e => handleInputChange('offset', e.target.value)}\n                placeholder=\"2\"\n                type=\"number\"\n                value={formValues.offset}\n              />\n\n              <NovaSelect\n                label=\"Button color scheme\"\n                onChange={e =>\n                  handleInputChange('colorScheme', e.target.value as NonNullable<DemoCustomizations['colorScheme']>)\n                }\n                options={buttonColors}\n                value={formValues.colorScheme}\n              />\n\n              <NovaSelect\n                label=\"Button size\"\n                onChange={e =>\n                  handleInputChange('buttonSize', e.target.value as NonNullable<DemoCustomizations['buttonSize']>)\n                }\n                options={buttonSizes}\n                value={formValues.buttonSize}\n              />\n\n              <NovaSelect\n                label=\"Placement\"\n                onChange={e => handleInputChange('placement', e.target.value as DemoCustomizations['placement'])}\n                options={placements}\n                value={formValues.placement}\n              />\n\n              <NovaCheckbox\n                checked={formValues.iconButton}\n                label=\"Icon button\"\n                description=\"It is recommended to use the small button size and tertiary color scheme with this option.\"\n                onChange={e => handleInputChange('iconButton', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.showPrefixIcons}\n                label=\"Show prefix icons\"\n                onChange={e => handleInputChange('showPrefixIcons', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.showSuffixIcons}\n                label=\"Show suffix icons\"\n                onChange={e => handleInputChange('showSuffixIcons', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.showToggleIcon}\n                label=\"Show toggle icon\"\n                onChange={e => handleInputChange('showToggleIcon', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaDropdownMenuDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable dropdown menu"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Dropdownmenu",
          "selector": "<DropdownMenu />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive element enabling users to select a single option from a list."
        },
        {
          "order": 2,
          "name": "Dropdownbutton",
          "selector": "<DropdownButton />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Button used to hide or show the dropdown menu."
        },
        {
          "order": 3,
          "name": "Dropdowncontainer",
          "selector": "<DropdownContainer />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container that styles the dropdown menu."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Dropdownmenu",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Scroll"
          }
        },
        {
          "name": "alternate",
          "section": "Dropdownbutton",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "Dropdownbutton",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "colorScheme",
          "section": "Dropdownbutton",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "Dropdownbutton",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "Dropdownbutton",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "Dropdownbutton",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "Dropdownbutton",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "Dropdownbutton",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "Dropdownbutton",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "Dropdownbutton",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "tag",
          "section": "Dropdowncontainer",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of the component"
          }
        }
      ]
    },
    {
      "name": "flag",
      "version": "0.0.1",
      "description": "Messages that provide low-priority updates about a process or event",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Informational flags",
          "description": "",
          "order": 1
        },
        {
          "name": "Success flags",
          "description": "",
          "order": 2
        },
        {
          "name": "Warning flags",
          "description": "",
          "order": 3
        },
        {
          "name": "Error flags",
          "description": "",
          "order": 4
        },
        {
          "name": "Custom flag",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/empty-information-flag",
            "github": "apps/workshop/src/examples/components/flag/empty-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Flag } from '@visa/nova-react';\n\nexport const EmptyInformationFlag = () => {\n  return <Flag />;\n};\n"
          },
          "name": "Empty informational flag"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/default-information-flag",
            "github": "apps/workshop/src/examples/components/flag/default-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader } from '@visa/nova-react';\n\nexport const DefaultInformationFlag = () => {\n  return (\n    <Flag>\n      <MessageIcon />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>information</ScreenReader>This is required text that describes the flag in more detail.\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Default informational flag"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/title-information-flag",
            "github": "apps/workshop/src/examples/components/flag/title-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const TitleInformationFlag = () => {\n  return (\n    <Flag>\n      <MessageIcon />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>information</ScreenReader>\n        <Typography variant=\"body-2-bold\">Informational title</Typography>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Informational flag with title"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/link-information-flag",
            "github": "apps/workshop/src/examples/components/flag/link-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, Link, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const LinkInformationFlag = () => {\n  return (\n    <Flag>\n      <MessageIcon />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>information</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Link href=\"./flag\">Destination label</Link>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Informational flag with link"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/button-information-flag",
            "github": "apps/workshop/src/examples/components/flag/button-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, Flag, FlagCloseButton, FlagContent, Typography, ScreenReader } from '@visa/nova-react';\n\nexport const ButtonInformationFlag = () => {\n  return (\n    <Flag>\n      <MessageIcon />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>information</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Informational flag with button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Informational flags",
          "url": {
            "iframe": "components/flag/persistent-information-flag",
            "github": "apps/workshop/src/examples/components/flag/persistent-information-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Flag, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const PersistentInformationFlag = () => {\n  return (\n    <Flag>\n      <MessageIcon />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>information</ScreenReader>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n    </Flag>\n  );\n};\n"
          },
          "name": "Informational flag without close icon button"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/empty-success-flag",
            "github": "apps/workshop/src/examples/components/flag/empty-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Flag } from '@visa/nova-react';\n\nexport const EmptySuccessFlag = () => {\n  return <Flag messageType=\"success\" />;\n};\n"
          },
          "name": "Empty success flag"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/default-success-flag",
            "github": "apps/workshop/src/examples/components/flag/default-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader } from '@visa/nova-react';\n\nexport const DefaultSuccessFlag = () => {\n  return (\n    <Flag messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>success</ScreenReader>This is required text that describes the flag in more detail.\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Default success flag"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/title-success-flag",
            "github": "apps/workshop/src/examples/components/flag/title-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const TitleSuccessFlag = () => {\n  return (\n    <Flag messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>success</ScreenReader>\n        <Typography variant=\"body-2-bold\">Success title</Typography>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Success flag with title"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/link-success-flag",
            "github": "apps/workshop/src/examples/components/flag/link-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, Link, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const LinkSuccessFlag = () => {\n  return (\n    <Flag messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>success</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Link href=\"./flag\">Destination label</Link>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Success flag with link"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/button-success-flag",
            "github": "apps/workshop/src/examples/components/flag/button-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const ButtonSuccessFlag = () => {\n  return (\n    <Flag messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>success</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Success flag with button"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Success flags",
          "url": {
            "iframe": "components/flag/persistent-success-flag",
            "github": "apps/workshop/src/examples/components/flag/persistent-success-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Flag, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const PersistentSuccessFlag = () => {\n  return (\n    <Flag messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>success</ScreenReader>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n    </Flag>\n  );\n};\n"
          },
          "name": "Success flag without close icon button"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/empty-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/empty-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Flag } from '@visa/nova-react';\n\nexport const EmptyWarningFlag = () => {\n  return <Flag messageType=\"warning\" />;\n};\n"
          },
          "name": "Empty warning flag"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/default-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/default-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader } from '@visa/nova-react';\n\nexport const DefaultWarningFlag = () => {\n  return (\n    <Flag messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>warning</ScreenReader>This is required text that describes the flag in more detail.\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Default warning flag"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/title-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/title-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const TitleWarningFlag = () => {\n  return (\n    <Flag messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>warning</ScreenReader>\n        <Typography variant=\"body-2-bold\">Warning title</Typography>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Warning flag with title"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/link-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/link-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, Link, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const LinkWarningFlag = () => {\n  return (\n    <Flag messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>warning</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Link href=\"./flag\">Destination label</Link>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Warning flag with link"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/button-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/button-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const ButtonWarningFlag = () => {\n  return (\n    <Flag messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>warning</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Warning flag with button"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Warning flags",
          "url": {
            "iframe": "components/flag/persistent-warning-flag",
            "github": "apps/workshop/src/examples/components/flag/persistent-warning-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Flag, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const PersistentWarningFlag = () => {\n  return (\n    <Flag messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>warning</ScreenReader>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n    </Flag>\n  );\n};\n"
          },
          "name": "Warning flag without close icon button"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/empty-error-flag",
            "github": "apps/workshop/src/examples/components/flag/empty-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Flag } from '@visa/nova-react';\n\nexport const EmptyErrorFlag = () => {\n  return <Flag messageType=\"error\" />;\n};\n"
          },
          "name": "Empty error flag"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/default-error-flag",
            "github": "apps/workshop/src/examples/components/flag/default-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader } from '@visa/nova-react';\n\nexport const DefaultErrorFlag = () => {\n  return (\n    <Flag messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>error</ScreenReader>\n        This is required text that describes the flag in more detail.\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Default error flag"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/title-error-flag",
            "github": "apps/workshop/src/examples/components/flag/title-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const TitleErrorFlag = () => {\n  return (\n    <Flag messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>error</ScreenReader>\n        <Typography variant=\"body-2-bold\">Error title</Typography>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Error flag with title"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/link-error-flag",
            "github": "apps/workshop/src/examples/components/flag/link-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Flag, FlagCloseButton, FlagContent, Link, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const LinkErrorFlag = () => {\n  return (\n    <Flag messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>error</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Link href=\"./flag\">Destination label</Link>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Error flag with link"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/button-error-flag",
            "github": "apps/workshop/src/examples/components/flag/button-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, Flag, FlagCloseButton, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const ButtonErrorFlag = () => {\n  return (\n    <Flag messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>error</ScreenReader>\n        <Typography className=\"v-mb-8\">This is required text that describes the flag in more detail.</Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </FlagContent>\n      <FlagCloseButton>\n        <VisaCloseTiny />\n      </FlagCloseButton>\n    </Flag>\n  );\n};\n"
          },
          "name": "Error flag with button"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Error flags",
          "url": {
            "iframe": "components/flag/persistent-error-flag",
            "github": "apps/workshop/src/examples/components/flag/persistent-error-flag.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { Flag, FlagContent, ScreenReader, Typography } from '@visa/nova-react';\n\nexport const PersistentErrorFlag = () => {\n  return (\n    <Flag messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n        <ScreenReader>error</ScreenReader>\n        <Typography>This is required text that describes the flag in more detail.</Typography>\n      </FlagContent>\n    </Flag>\n  );\n};\n"
          },
          "name": "Error flag without close icon button"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Custom flag",
          "url": {
            "iframe": "components/flag/reusable",
            "github": "apps/workshop/src/examples/components/flag/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Flag,\n  FlagCloseButton,\n  FlagContent,\n  type FlagProperties,\n  Link,\n  type MessageType,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type ReactNode, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Nova Flag Component Props\nexport type NovaFlagProps = FlagProperties & {\n  buttonLabel?: string;\n  description?: string;\n  dismissible?: boolean;\n  href?: string;\n  icon?: ReactNode;\n  linkLabel?: string;\n  onButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n  onClose?: () => void;\n  showIcon?: boolean;\n  title?: string;\n  titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n};\n\n// Main Nova Flag Component\nexport const NovaFlag = ({\n  buttonLabel,\n  children,\n  description,\n  dismissible = false,\n  href,\n  icon,\n  linkLabel,\n  messageType,\n  onButtonClick,\n  onClose,\n  showIcon = false,\n  title,\n  titleTag: Title = 'h4',\n  ...remainingProps\n}: NovaFlagProps) => {\n  return (\n    <Flag messageType={messageType} {...remainingProps}>\n      {showIcon && <MessageIcon messageType={messageType as Parameters<typeof MessageIcon>[0]['messageType']} />}\n      {icon}\n\n      <UtilityFragment vPaddingBottom={2} vPaddingLeft={2}>\n        <FlagContent>\n          {title && <Title className=\"v-typography-body-2-bold\">{title}</Title>}\n          {description && <p>{description}</p>}\n          {buttonLabel && (\n            <UtilityFragment vMarginRight={linkLabel ? 8 : 0} vMarginTop={8}>\n              <Button colorScheme=\"secondary\" onClick={onButtonClick}>\n                {buttonLabel}\n              </Button>\n            </UtilityFragment>\n          )}\n          {linkLabel && <Link href={href}>{linkLabel}</Link>}\n          {children}\n        </FlagContent>\n      </UtilityFragment>\n\n      {dismissible && (\n        <FlagCloseButton aria-label=\"close\" onClick={onClose}>\n          <VisaCloseTiny />\n        </FlagCloseButton>\n      )}\n    </Flag>\n  );\n};\n\n// export default NovaFlag;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  buttonLabel: string;\n  description: string;\n  dismissible: boolean;\n  href: string;\n  linkLabel: string;\n  messageType: MessageType;\n  showIcon: boolean;\n  title: string;\n  titleTag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n}\n\n// Demo Component\nexport const NovaFlagDemo = () => {\n  const messageTypes: { label: string; value: MessageType }[] = [\n    { label: 'Success', value: 'success' },\n    { label: 'Information', value: 'information' },\n    { label: 'Warning', value: 'warning' },\n    { label: 'Error', value: 'error' },\n    { label: 'Subtle', value: 'subtle' },\n  ];\n\n  const titleTags: { label: string; value: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' }[] = [\n    { label: '1', value: 'h1' },\n    { label: '2', value: 'h2' },\n    { label: '3', value: 'h3' },\n    { label: '4', value: 'h4' },\n    { label: '5', value: 'h5' },\n    { label: '6', value: 'h6' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    buttonLabel: '',\n    description: 'This is required text that describes the flag in more detail.',\n    dismissible: true,\n    href: 'www.visa.com',\n    linkLabel: '',\n    messageType: 'success',\n    showIcon: true,\n    title: 'Success title',\n    titleTag: 'h4',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  const handleClose = () => {\n    console.log('Section message closed');\n  };\n\n  const handleClick = () => {\n    console.log('Section message button clicked');\n  };\n\n  return (\n    <div>\n      <NovaFlag\n        buttonLabel={customizations.buttonLabel || ''}\n        description={customizations.description || ''}\n        dismissible={customizations.dismissible}\n        href={customizations.href || ''}\n        linkLabel={customizations.linkLabel || ''}\n        messageType={customizations.messageType}\n        onButtonClick={handleClick}\n        onClose={handleClose}\n        showIcon={customizations.showIcon}\n        title={customizations.title || ''}\n        titleTag={customizations.titleTag}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Button label\"\n                onChange={e => handleInputChange('buttonLabel', e.target.value)}\n                value={formValues.buttonLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Href\"\n                onChange={e => handleInputChange('href', e.target.value)}\n                value={formValues.href}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Link label\"\n                onChange={e => handleInputChange('linkLabel', e.target.value)}\n                value={formValues.linkLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Title\"\n                onChange={e => handleInputChange('title', e.target.value)}\n                value={formValues.title}\n              />\n\n              <NovaSelect\n                label=\"Message type\"\n                onChange={e => handleInputChange('messageType', e.target.value as MessageType)}\n                options={messageTypes}\n                value={formValues.messageType}\n              />\n\n              <NovaSelect\n                label=\"Title level\"\n                onChange={e => handleInputChange('titleTag', e.target.value as DemoCustomizations['titleTag'])}\n                options={titleTags}\n                value={formValues.titleTag}\n              />\n\n              <NovaCheckbox\n                checked={formValues.dismissible}\n                label=\"Dismissible\"\n                onChange={e => handleInputChange('dismissible', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                checked={formValues.showIcon}\n                label=\"Show icon\"\n                onChange={e => handleInputChange('showIcon', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaFlagDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable flag"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Flag",
          "selector": "<Flag />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Messages that provide low-priority updates about a process or event"
        },
        {
          "order": 2,
          "name": "FlagCloseButton",
          "selector": "<FlagCloseButton />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Close button to dismiss a flag message."
        },
        {
          "order": 3,
          "name": "Messagecontent",
          "selector": "<MessageContent />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for message content elements."
        }
      ],
      "properties": [
        {
          "name": "messageType",
          "section": "Flag",
          "data": {
            "name": "messageType",
            "type": "\"subtle\" , \"warning\" , \"error\" , \"information\" , \"success\"",
            "default": "",
            "required": "false",
            "description": "Message Type"
          }
        },
        {
          "name": "tag",
          "section": "Flag",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "FlagCloseButton",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "FlagCloseButton",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "children",
          "section": "FlagCloseButton",
          "data": {
            "name": "children",
            "type": "ReactNode",
            "default": "",
            "required": "false",
            "description": "@required"
          }
        },
        {
          "name": "colorScheme",
          "section": "FlagCloseButton",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "FlagCloseButton",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "FlagCloseButton",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "FlagCloseButton",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "FlagCloseButton",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "FlagCloseButton",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "FlagCloseButton",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "FlagCloseButton",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "tag",
          "section": "Messagecontent",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "footer",
      "version": "0.0.1",
      "description": "Content anchored at the bottom of a page to provide important information or links.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Examples",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/footer/default-footer",
            "github": "apps/workshop/src/examples/components/footer/default-footer.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "// If you are using Vite to run your application, please follow the instruction on the top of the page.\nimport { Footer, Link, Utility, VisaLogo } from '@visa/nova-react';\n\nexport const DefaultFooter = () => {\n  return (\n    <Footer className=\"v-gap-15\">\n      <Utility vFlex vMarginRight={1}>\n        <VisaLogo aria-label=\"Visa\" />\n      </Utility>\n      <Utility vFlex vFlexWrap vFlexGrow vJustifyContent=\"between\" vGap={42}>\n        {`Copyright © ${new Date().getFullYear()} Visa Inc. All Rights Reserved`}\n        <Utility tag=\"ul\" vFlex vFlexWrap vGap={16}>\n          <li>\n            <Link href=\"/footer\">Contact us</Link>\n          </li>\n          <li>\n            <Link href=\"/footer\">Privacy</Link>\n          </li>\n          <li>\n            <Link href=\"/footer\">Legal/terms and conditions</Link>\n          </li>\n        </Utility>\n      </Utility>\n    </Footer>\n  );\n};\n"
          },
          "name": "Default footer"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/footer/navigational-footer",
            "github": "apps/workshop/src/examples/components/footer/navigational-footer.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "// If you are using Vite to run your application, please follow the instruction on the top of the page.\nimport { Footer, Link, Typography, Utility, UtilityFragment, VisaLogo } from '@visa/nova-react';\n\nexport const NavigationalFooter = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={24} vPadding={24}>\n      <Footer>\n        <Utility vFlex vFlexCol vFlexGrow vFlexShrink0 vGap={24} style={{ flexBasis: 'calc(30% - 32px)' }}>\n          <VisaLogo aria-label=\"Visa\" />\n          <p>\n            The information furnished here is confidential and to be used solely for the support of clients' Visa\n            programs. This information shall not be duplicated, published, or disclosed, in whole or in part, without\n            the prior written permission of Visa.\n          </p>\n          <Typography colorScheme=\"subtle\">Copyright &copy; YYYY-YYYY Visa. All rights reserved.</Typography>\n        </Utility>\n        <Utility vFlex vFlexGrow vFlexWrap vGap={24}>\n          <Utility vFlex vFlexCol vFlexGrow vGap={24} style={{ flexBasis: 'calc(15% - 32px)' }}>\n            <Typography tag=\"h2\" variant=\"body-2-bold\">\n              Visa Inc.\n            </Typography>\n            <Utility tag=\"ul\" vFlex vFlexCol vGap={16}>\n              <li>\n                <Link href=\"./footer\">Privacy</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">Terms of use</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">About Visa</Link>\n              </li>\n            </Utility>\n          </Utility>\n          <Utility vFlex vFlexCol vFlexGrow vGap={24} style={{ flexBasis: 'calc(15% - 32px)' }}>\n            <Typography tag=\"h2\" variant=\"body-2-bold\">\n              Support\n            </Typography>\n            <Utility tag=\"ul\" vFlex vFlexCol vGap={16}>\n              <li>\n                <Link href=\"./footer\">FAQs</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">Feedback/Contact Us</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">Online help</Link>\n              </li>\n            </Utility>\n          </Utility>\n          <Utility vFlex vFlexCol vFlexGrow vGap={24} style={{ flexBasis: 'calc(15% - 32px)' }}>\n            <Typography tag=\"h2\" variant=\"body-2-bold\">\n              Update profile\n            </Typography>\n            <Utility tag=\"ul\" vFlex vFlexCol vGap={16}>\n              <li>\n                <Link href=\"./footer\">My information</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">My security</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">My services</Link>\n              </li>\n            </Utility>\n          </Utility>\n          <Utility vFlex vFlexCol vFlexGrow vGap={24} style={{ flexBasis: 'calc(15% - 32px)' }}>\n            <Typography tag=\"h2\" variant=\"body-2-bold\">\n              Site index\n            </Typography>\n            <Utility tag=\"ul\" vFlex vFlexCol vGap={16}>\n              <li>\n                <Link href=\"./footer\">Alphabetized index</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">Site map</Link>\n              </li>\n              <li>\n                <Link href=\"./footer\">Topic index</Link>\n              </li>\n            </Utility>\n          </Utility>\n        </Utility>\n      </Footer>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Navigational footer"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Footer",
          "selector": "<Footer />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Content anchored at the bottom of a page to provide important information or links."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Footer",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "footer",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "horizontal-navigation",
      "version": "0.0.1",
      "description": "Menu or panel at the top of page content that links to important pages or features.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default horizontal navigations",
          "description": "",
          "order": 1
        },
        {
          "name": "Horizontal navigations with persistent search",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/default-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/default-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  offset,\n  FloatingFocusManager,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const DefaultHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement>(null);\n  const searchButtonRef = useRef<HTMLButtonElement>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n  \n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(8)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-label=\"open menu\"\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for horizontal default example\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal default example\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }} tag=\"sup\">\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Default horizontal navigation"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/active-element-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/active-element-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'active-element-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const ActiveElementHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement>(null);\n  const searchButtonRef = useRef<HTMLButtonElement>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for horizontal example with active element\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          aria-current=\"page\"\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal example with active element\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }} tag=\"sup\">\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Horizontal navigation with active element"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/horizontal-with-icons",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/horizontal-with-icons.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\n\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n  VisaSecurityTiny,\n  VisaSettingsTiny,\n  VisaStatisticsTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const DefaultHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for horizontal example with icons\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">{<VisaStatisticsTiny />}L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">{<VisaSettingsTiny />}L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          <VisaSecurityTiny />\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-describedby={`${id}-notifications-badge`}\n                    aria-label=\"notifications\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal example with icons\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }} tag=\"sup\">\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Horizontal navigation with icons"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/alternate-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/alternate-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const AlternateHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement>(null);\n  const searchButtonRef = useRef<HTMLButtonElement>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link alternate skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} alternate orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for alternate horizontal example\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  ref={searchButtonRef}\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          alternate\n          aria-label=\"Label for alternate horizontal example\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge\n                  badgeVariant=\"number\"\n                  style={\n                    {\n                      position: 'relative',\n                    } as CSSProperties\n                  }\n                  tag=\"sup\"\n                >\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate horizontal navigation"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/alternate-active-element-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/alternate-active-element-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-active-element-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const AlternateActiveElementHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link alternate skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} alternate orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for alternate horizontal example with active element\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          aria-current=\"page\"\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          alternate\n          aria-label=\"Label for alternate horizontal example with active element\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 3</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }} tag=\"sup\">\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate horizontal navigation with active element"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/alternate-horizontal-with-icons",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/alternate-horizontal-with-icons.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\n\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n  VisaSecurityTiny,\n  VisaSettingsTiny,\n  VisaStatisticsTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-horizontal-nav-with-icons';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const AlternateHorizontalNavWithIcons = () => {\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link alternate skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} alternate orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for alternate horizontal example with icons\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">{<VisaStatisticsTiny />}L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">{<VisaSettingsTiny />}L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          <VisaSecurityTiny />\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          alternate\n          aria-label=\"Label for alternate horizontal example with icons\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge\n                  badgeVariant=\"number\"\n                  tag=\"sup\"\n                  style={\n                    {\n                      position: 'relative',\n                    } as CSSProperties\n                  }\n                >\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate horizontal navigation with icons"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default horizontal navigations",
          "url": {
            "iframe": "components/horizontal-navigation/stacked-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/stacked-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'stacked-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const StackedHorizontalNav = () => {\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [expandSearch, setExpandSearch] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  buttonSize=\"large\"\n                  ref={searchButtonRef}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => { setExpandSearch(true); searchInitiallyActivated.current = true; }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <Nav\n        aria-label=\"Label for horizontal example with stacked menu\"\n        className=\"v-ml-auto v-mobile-container-hide\"\n        style={\n          {\n            '--v-surface-background': 'var(--palette-default-surface-2)',\n            '--v-tabs-active-line-padding': 'var(--size-responsive-10)',\n          } as CSSProperties\n        }\n      >\n        <Tabs className=\"v-gap-8\">\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n            />\n          </Tab>\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n            />\n          </Tab>\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 3</a>}\n            />\n          </Tab>\n        </Tabs>\n      </Nav>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal example with stacked menu\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 3</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }}>\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Stacked horizontal navigation"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal navigations with persistent search",
          "url": {
            "iframe": "components/horizontal-navigation/search-persistent-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/search-persistent-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseTiny,\n  VisaCloseLow,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useEffect, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'search-persistent-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nconst label3SubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const SearchPersistentHorizontalNav = () => {\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel3MenuOpen, setMobileLabel3MenuOpen] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [label3Open, setLabel3Open] = useState(false);\n\n  const mobileSearchInputRef = useRef<HTMLInputElement | null>(null);\n  const mobileSearchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [expandSearch, setExpandSearch] = useState(false);\n\n  useEffect(() => {\n    if (expandSearch) {\n      mobileSearchInputRef.current?.focus();\n    }\n    if (!expandSearch) {\n      mobileSearchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // floating-ui setup for the label3 tab dropdown\n  const {\n    context: label3FloatingContext,\n    floatingStyles: label3FloatingStyles,\n    refs: label3FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label3Open,\n    onOpenChange: setLabel3Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel3Ref = useClick(label3FloatingContext);\n  const dismissLabel3Menu = useDismiss(label3FloatingContext);\n  const { getReferenceProps: getLabel3ReferenceProps, getFloatingProps: getLabel3FloatingProps } = useInteractions([\n    clickLabel3Ref,\n    dismissLabel3Menu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                        tag=\"sup\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"Label for horizontal example with persistent search\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label3Open}\n                          aria-controls={label3Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label3FloatingRefs.setReference}\n                          {...getLabel3ReferenceProps()}\n                        >\n                          L1 label 3<TabSuffix element={label3Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label3Open && (\n                          <FloatingFocusManager\n                            context={label3FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label3Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label3FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label3FloatingRefs.setFloating}\n                              {...getLabel3FloatingProps()}\n                            >\n                              <Listbox>\n                                {label3SubItems.map(label3SubItem => (\n                                  <li key={label3SubItem.id}>\n                                    <ListboxItem<'a'> href={label3SubItem.href} tag=\"a\">\n                                      {label3SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <UtilityFragment vFlexRow vContainerHide=\"mobile\">\n                  <InputContainer>\n                    <VisaSearchLow />\n                    <Input\n                      id={`${id}-search-field`}\n                      name={`${id}-search-field`}\n                      required\n                      type=\"search\"\n                      aria-label=\"Search\"\n                      placeholder=\"Search\"\n                    />\n                  </InputContainer>\n                </UtilityFragment>\n                <UtilityFragment vFlexRow vContainerHide=\"desktop\">\n                  <Button\n                    aria-label=\"search site\"\n                    buttonSize=\"large\"\n                    ref={mobileSearchButtonRef}\n                    colorScheme=\"tertiary\"\n                    iconButton\n                    onClick={() => {\n                      setExpandSearch(true);\n                    }}\n                  >\n                    <VisaSearchLow />\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\" vPaddingBottom={0}>\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={mobileSearchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal example with persistent search\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel3MenuOpen}\n                aria-controls={mobileLabel3MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel3MenuOpen(!mobileLabel3MenuOpen)}\n              >\n                L1 Label 3\n                <TabSuffix element={mobileLabel3MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel3MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label3SubItems.map(label3SubItem => (\n                    <Tab key={label3SubItem.id} id={label3SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label3SubItem.href}>{label3SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }} tag=\"sup\">\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Default horizontal navigation with persistent search"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal navigations with persistent search",
          "url": {
            "iframe": "components/horizontal-navigation/stacked-search-persistent-horizontal-nav",
            "github": "apps/workshop/src/examples/components/horizontal-navigation/stacked-search-persistent-horizontal-nav.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseTiny,\n  VisaCloseLow,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useEffect, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'stacked-search-persistent-horizontal-nav';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './horizontal-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './horizontal-navigation',\n  },\n];\n\nexport const StackedSearchPersistentHorizontalNav = () => {\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n\n  const mobileSearchInputRef = useRef<HTMLInputElement | null>(null);\n  const mobileSearchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const [expandSearch, setExpandSearch] = useState(false);\n\n  useEffect(() => {\n    if (expandSearch) {\n      mobileSearchInputRef.current?.focus();\n    }\n    if (!expandSearch) {\n      mobileSearchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // For dropdown menus in the horizontal nav, we use floating UI for\n  // -opening\n  // -positioning\n  // -dismissing\n\n  // floating-ui setup for the account dropdown\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {!expandSearch ? (\n            <>\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-describedby={`${id}-mobile-menu-notifications-badge`}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                      <Badge\n                        id={`${id}-mobile-menu-notifications-badge`}\n                        aria-label=\"3 notifications\"\n                        badgeVariant=\"number\"\n                      >\n                        3\n                      </Badge>\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./horizontal-navigation\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Utility\n                      vContainerHide=\"xs\"\n                      element={<Typography variant=\"headline-3\">Application Name</Typography>}\n                    />\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <UtilityFragment vFlexRow vContainerHide=\"xs\">\n                  <InputContainer>\n                    <VisaSearchLow />\n                    <Input\n                      id={`${id}-search-field`}\n                      name={`${id}-search-field`}\n                      required\n                      type=\"search\"\n                      aria-label=\"Search\"\n                      placeholder=\"Search\"\n                    />\n                  </InputContainer>\n                </UtilityFragment>\n                <UtilityFragment vFlexRow vContainerHide=\"desktop\">\n                  <Button\n                    aria-label=\"search site\"\n                    buttonSize=\"large\"\n                    ref={mobileSearchButtonRef}\n                    colorScheme=\"tertiary\"\n                    iconButton\n                    onClick={() => {\n                      setExpandSearch(true);\n                    }}\n                  >\n                    <VisaSearchLow />\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                <UtilityFragment vContainerHide=\"mobile\" vPaddingBottom={0}>\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={mobileSearchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n\n      <Nav\n        aria-label=\"Label for horizontal example with stacked menu and persistent search\"\n        className=\"v-ml-auto v-mobile-container-hide\"\n        style={\n          {\n            '--v-surface-background': 'var(--palette-default-surface-2)',\n            '--v-tabs-active-line-padding': 'var(--size-responsive-10)',\n          } as CSSProperties\n        }\n      >\n        <Tabs className=\"v-gap-8\">\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n            />\n          </Tab>\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n            />\n          </Tab>\n          <Tab>\n            <Button\n              buttonSize=\"large\"\n              colorScheme=\"tertiary\"\n              element={<a href=\"./horizontal-navigation\">L1 label 3</a>}\n            />\n          </Tab>\n        </Tabs>\n      </Nav>\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          aria-label=\"Label for horizontal example with stacked menu and persistent search\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./horizontal-navigation\">L1 label 3</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge badgeVariant=\"number\" style={{ position: 'relative' }}>\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n            <Divider dividerType=\"decorative\"></Divider>\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </Tabs>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Stacked horizontal navigation with persistent search"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Nav",
          "selector": "<Nav />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Menu or panel at the top or next to page content that links to important pages or features."
        },
        {
          "order": 2,
          "name": "tabs",
          "type": "related",
          "selector": "<Tabs />",
          "description": ""
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Nav",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate"
          }
        },
        {
          "name": "drawer",
          "section": "Nav",
          "data": {
            "name": "drawer",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Drawer"
          }
        },
        {
          "name": "orientation",
          "section": "Nav",
          "data": {
            "name": "orientation",
            "type": "\"horizontal\" , \"vertical\"",
            "default": "",
            "required": "false",
            "description": "Orientation"
          }
        },
        {
          "name": "tag",
          "section": "Nav",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "nav",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "icon",
      "version": "0.0.1",
      "description": "Meant for use with sprites only. Uses dom href linking of sprite elements expected to already be in the DOM to render the icon.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Icon styles",
          "description": "",
          "order": 1
        },
        {
          "name": "Icon sizes",
          "description": "",
          "order": 2
        },
        {
          "name": "Icon customizations",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Icon styles",
          "url": {
            "iframe": "components/icon/default-icon",
            "github": "apps/workshop/src/examples/components/icon/default-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaGlobalLow } from '@visa/nova-icons-react';\n\nexport const DefaultIcon = () => {\n  return <VisaGlobalLow aria-hidden=\"false\" aria-label=\"global\" />;\n};\n"
          },
          "name": "Default"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Icon styles",
          "url": {
            "iframe": "components/icon/visa-icon",
            "github": "apps/workshop/src/examples/components/icon/visa-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationLow } from '@visa/nova-icons-react';\n\nexport const VisaIcon = () => {\n  return <VisaInformationLow aria-hidden=\"false\" aria-label=\"info\" />;\n};\n"
          },
          "name": "Visa"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Icon styles",
          "url": {
            "iframe": "components/icon/generic-icon",
            "github": "apps/workshop/src/examples/components/icon/generic-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { GenericInformationLow } from '@visa/nova-icons-react';\n\nexport const GenericIcon = () => {\n  return <GenericInformationLow aria-hidden=\"false\" aria-label=\"info\" />;\n};\n"
          },
          "name": "Generic"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Icon sizes",
          "url": {
            "iframe": "components/icon/tiny-resolution",
            "github": "apps/workshop/src/examples/components/icon/tiny-resolution.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationTiny } from '@visa/nova-icons-react';\n\nexport const TinyResolution = () => {\n  return <VisaInformationTiny aria-hidden=\"false\" aria-label=\"info\" />;\n};\n"
          },
          "name": "Tiny resolution"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Icon sizes",
          "url": {
            "iframe": "components/icon/low-resolution",
            "github": "apps/workshop/src/examples/components/icon/low-resolution.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationLow } from '@visa/nova-icons-react';\n\nexport const LowResolution = () => {\n  return <VisaInformationLow aria-hidden=\"false\" aria-label=\"info\" />;\n};\n"
          },
          "name": "Low resolution"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Icon sizes",
          "url": {
            "iframe": "components/icon/high-resolution",
            "github": "apps/workshop/src/examples/components/icon/high-resolution.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaInformationHigh } from '@visa/nova-icons-react';\n\nexport const HighResolution = () => {\n  return <VisaInformationHigh aria-hidden=\"false\" aria-label=\"info\" />;\n};\n"
          },
          "name": "High resolution"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Icon customizations",
          "url": {
            "iframe": "components/icon/rtl-icon",
            "github": "apps/workshop/src/examples/components/icon/rtl-icon.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronRightLow } from '@visa/nova-icons-react';\n\nexport const RtlIcons = () => {\n  return <VisaChevronRightLow rtl />;\n};\n"
          },
          "name": "Icon with right-to-left support"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Icon customizations",
          "url": {
            "iframe": "components/icon/custom-color-icon",
            "github": "apps/workshop/src/examples/components/icon/custom-color-icon.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaHomeHigh } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\n\nexport const CustomColorIcon = () => {\n  return <VisaHomeHigh style={{ '--v-icon-primary': 'teal', '--v-icon-secondary': 'orange' } as CSSProperties} />;\n};\n"
          },
          "name": "Icon with custom colors"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Icon",
          "selector": "<Icon />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Meant for use with sprites only. Uses dom href linking of sprite elements expected to already be in the DOM to render the icon."
        }
      ],
      "properties": [
        {
          "name": "ariaBaseId",
          "section": "Icon",
          "data": {
            "name": "ariaBaseId",
            "type": "string , number",
            "default": "",
            "required": "false",
            "description": "Aria Base ID"
          }
        },
        {
          "name": "brand",
          "section": "Icon",
          "data": {
            "name": "brand",
            "type": "\"generic\" , \"visa\"",
            "default": "generic",
            "required": "false",
            "description": "Icon Branding"
          }
        },
        {
          "name": "description",
          "section": "Icon",
          "data": {
            "name": "description",
            "type": "string",
            "default": "",
            "required": "false",
            "description": "Description for Standalone SVG's"
          }
        },
        {
          "name": "iconName",
          "section": "Icon",
          "data": {
            "name": "iconName",
            "type": "string",
            "default": "help",
            "required": "false",
            "description": "Name of Icon"
          }
        },
        {
          "name": "resolution",
          "section": "Icon",
          "data": {
            "name": "resolution",
            "type": "\"low\" , \"high\" , \"tiny\"",
            "default": "low",
            "required": "false",
            "description": "Resolution of Icon"
          }
        },
        {
          "name": "rtl",
          "section": "Icon",
          "data": {
            "name": "rtl",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Flips icon horizontally when document direction is set to right to left"
          }
        },
        {
          "name": "title",
          "section": "Icon",
          "data": {
            "name": "title",
            "type": "string",
            "default": "",
            "required": "false",
            "description": "Title for Standalone SVG's"
          }
        }
      ]
    },
    {
      "name": "input",
      "version": "0.0.1",
      "description": "Text fields that enable users to enter free-form content.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Single-line inputs",
          "description": "",
          "order": 1
        },
        {
          "name": "Multi-line inputs",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom inputs",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/default-input",
            "github": "apps/workshop/src/examples/components/input/default-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-default';\n\nexport const DefaultInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-required=\"true\" id={id} type=\"text\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default input"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/initial-value-input",
            "github": "apps/workshop/src/examples/components/input/initial-value-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-initial-value';\n\nexport const InitialValueInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-required=\"true\" defaultValue=\"Initial value\" id={id} type=\"text\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with initial value"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/inline-message-input",
            "github": "apps/workshop/src/examples/components/input/inline-message-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-inline-message';\n\nexport const InlineMessageInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-describedby={`${id}-message`} aria-required=\"true\" id={id} type=\"text\" />\n      </InputContainer>\n      <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with inline message"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/clear-button-input",
            "github": "apps/workshop/src/examples/components/input/clear-button-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Button, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useEffect, useRef, useState, type FocusEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-clear-button';\n\nexport const ClearButtonInput = () => {\n  const [showClearButton, setShowClearButton] = useState(false);\n  const [inputValue, setInputValue] = useState('');\n\n  const inputRef = useRef<HTMLInputElement>(null);\n\n  const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n    if (!event.currentTarget.contains(event.relatedTarget)) {\n      setShowClearButton(false);\n    }\n  };\n\n  const handleClear = () => {\n    setInputValue('');\n    // Put focus back into the input\n    if (inputRef.current) {\n      inputRef.current.focus();\n    }\n  };\n\n  useEffect(() => {\n    if (inputValue !== '') setShowClearButton(true);\n    else setShowClearButton(false);\n  }, [inputValue]);\n\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer\n        onBlur={e => handleBlur(e)}\n        onFocus={() => {\n          if (inputValue !== '') setShowClearButton(true);\n        }}\n      >\n        <Input\n          ref={inputRef}\n          aria-required=\"true\"\n          id={id}\n          onChange={e => setInputValue(e.currentTarget.value)}\n          type=\"text\"\n          value={inputValue}\n        />\n        {showClearButton && (\n          <Button aria-label=\"Clear\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton onClick={handleClear} subtle>\n            <VisaClearAltTiny />\n          </Button>\n        )}\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with clear text button"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/read-only-input",
            "github": "apps/workshop/src/examples/components/input/read-only-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-readonly';\n\nexport const ReadOnlyInput = () => {\n  const [readonly, setReadonly] = useState(true);\n\n  return (\n    <>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Input aria-required=\"true\" defaultValue=\"Read-only example text.\" id={id} readOnly={readonly} type=\"text\" />\n        </InputContainer>\n      </Utility>\n      <Utility vAlignItems=\"center\" vFlex vGap={2} vMarginTop={24}>\n        <Checkbox checked={readonly} id={`${id}-checkbox`} onChange={() => setReadonly(!readonly)} />\n        <Label htmlFor={`${id}-checkbox`}>Mark input as read-only</Label>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Read-only input"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/disabled-input",
            "github": "apps/workshop/src/examples/components/input/disabled-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Checkbox, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-input';\n\nexport const DisabledInput = () => {\n  const [disabled, setDisabled] = useState(true);\n\n  return (\n    <>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Input aria-required=\"true\" disabled={disabled} id={id} type=\"text\" />\n        </InputContainer>\n      </Utility>\n      <Utility vAlignItems=\"center\" vFlex vGap={2} vMarginTop={24}>\n        <Checkbox checked={disabled} id={`${id}-checkbox`} onChange={() => setDisabled(!disabled)} />\n        <Label htmlFor={`${id}-checkbox`}>Mark input as disabled</Label>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Disabled input"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/error-input",
            "github": "apps/workshop/src/examples/components/input/error-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useRef, useState, type ChangeEvent } from 'react';\nimport { Button, Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-error';\n\nconst DEFAULT_INPUT_STATE = {\n  value: '',\n  error: false,\n};\n\nexport const ErrorInput = () => {\n  const [inputState, setInputState] = useState(DEFAULT_INPUT_STATE);\n\n  const inputRef = useRef<HTMLInputElement>(null);\n\n  const handleSubmit = () => {\n    // Customize this for your own validation needs\n    setInputState(prevInputState => ({\n      ...prevInputState,\n      error: true,\n    }));\n\n    // Focus on the input with error\n    if (inputRef.current) {\n      inputRef.current.focus();\n    }\n  };\n\n  const handleReset = () => {\n    setInputState(DEFAULT_INPUT_STATE);\n  };\n  const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n    setInputState({\n      value: e.target.value,\n      error: false,\n    });\n  };\n\n  return (\n    <>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Input\n            aria-describedby={`${id}-message`}\n            aria-invalid={inputState.error}\n            aria-required=\"true\"\n            ref={inputRef}\n            id={id}\n            type=\"text\"\n            value={inputState.value}\n            onChange={handleInputChange}\n          />\n        </InputContainer>\n        {inputState.error && (\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\">\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </Utility>\n      <Utility vFlex vGap={12} vMarginTop={16}>\n        <Button id={`${id}-submit-button`} onClick={handleSubmit}>\n          Submit\n        </Button>\n        <Button id={`${id}-reset-button`} colorScheme=\"secondary\" onClick={handleReset}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Input with error"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/prefix-input",
            "github": "apps/workshop/src/examples/components/input/prefix-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-prefix';\n\nexport const PrefixInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Typography id={`${id}-prefix`} tag=\"span\" variant=\"body-2-bold\">\n          $\n        </Typography>\n        <Input aria-describedby={`${id}-prefix`} aria-required=\"true\" id={id} type=\"text\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with prefix"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/suffix-input",
            "github": "apps/workshop/src/examples/components/input/suffix-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-suffix';\n\nexport const SuffixInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-describedby={`${id}-suffix`} aria-required=\"true\" id={id} type=\"text\" />\n        <Typography id={`${id}-suffix`} tag=\"span\" variant=\"body-2-bold\">\n          %\n        </Typography>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with suffix"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/action-button-input",
            "github": "apps/workshop/src/examples/components/input/action-button-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaPasswordHideTiny, VisaPasswordShowTiny } from '@visa/nova-icons-react';\nimport { Button, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-action-button';\n\nexport const ActionButtonInput = () => {\n  const [showPassword, setShowPassword] = useState(true);\n\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-required=\"true\" id={id} type={showPassword ? 'text' : 'password'} />\n        <Button\n          aria-label={showPassword ? 'hide text' : 'show text'}\n          buttonSize=\"small\"\n          colorScheme=\"tertiary\"\n          iconButton\n          onClick={() => setShowPassword(!showPassword)}\n        >\n          {showPassword ? <VisaPasswordHideTiny /> : <VisaPasswordShowTiny />}\n        </Button>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with action button"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/mask-button-input",
            "github": "apps/workshop/src/examples/components/input/mask-button-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaPasswordHideTiny, VisaPasswordShowTiny } from '@visa/nova-icons-react';\nimport { Button, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-mask-button';\n\nexport const MaskButtonInput = () => {\n  const [showPassword, setShowPassword] = useState(false);\n\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Input aria-required=\"true\" defaultValue=\"password\" id={id} type={showPassword ? 'text' : 'password'} />\n        <Button\n          aria-label={showPassword ? 'hide text' : 'show text'}\n          buttonSize=\"small\"\n          colorScheme=\"tertiary\"\n          iconButton\n          onClick={() => setShowPassword(!showPassword)}\n        >\n          {showPassword ? <VisaPasswordHideTiny /> : <VisaPasswordShowTiny />}\n        </Button>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with masked field"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/leading-icon-input",
            "github": "apps/workshop/src/examples/components/input/leading-icon-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaAccountLow } from '@visa/nova-icons-react';\nimport { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-leading-icon';\n\nexport const LeadingIconInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Utility vFlex vFlexCol>\n          <VisaAccountLow />\n        </Utility>\n        <Input aria-required=\"true\" id={id} type=\"text\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with leading icon"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Single-line inputs",
          "url": {
            "iframe": "components/input/one-time-passcode-input",
            "github": "apps/workshop/src/examples/components/input/one-time-passcode-input.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-otp';\n\nexport const OneTimePasscodeInput = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label</Label>\n      <InputContainer style={{ inlineSize: '160px' }}>\n        <Input aria-required=\"true\" id={id} otp type=\"text\" />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "One-time passcode input"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/native-resize-textarea",
            "github": "apps/workshop/src/examples/components/input/native-resize-textarea.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputContainer, Label, Textarea, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'native-text-area-resize';\n\nexport const NativeResizeTextarea = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer className=\"v-flex-row\">\n        <Textarea aria-required=\"true\" id={id} name={id} />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Native textarea with resize property"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/native-no-resize-textarea",
            "github": "apps/workshop/src/examples/components/input/native-no-resize-textarea.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputContainer, Label, Textarea, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'text-area-no-resize';\n\nexport const NativeNoResizeTextarea = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer className=\"v-flex-row\">\n        <Textarea aria-required=\"true\" fixed id={id} name={id} />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Native textarea without resize property"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/fixed-height-textarea",
            "github": "apps/workshop/src/examples/components/input/fixed-height-textarea.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { InputContainer, Label, Textarea, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'text-area-fixed-height';\n\nexport const FixedHeightTextarea = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer className=\"v-flex-row\">\n        <Textarea aria-required=\"true\" fixed id={id} name={id} style={{ blockSize: '130px' }} />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Textarea with fixed height"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/resize-textarea",
            "github": "apps/workshop/src/examples/components/input/resize-textarea.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { InputContainer, Label, Textarea, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'text-area-resize-height';\n\nexport const ResizeTextarea = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer className=\"v-flex-row\">\n        <Textarea aria-required=\"true\" id={id} name={id} style={{ blockSize: '130px' }} />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Textarea with fixed height and resize property"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/text-count-textarea",
            "github": "apps/workshop/src/examples/components/input/text-count-textarea.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputContainer, InputMessage, Label, Textarea, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useState, type ChangeEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'text-count-textarea';\nconst maxCharacters = 400;\n\nconst getMessage = ({\n  characterCount,\n  characterCountInvalid,\n  invalid,\n}: {\n  characterCount: number;\n  characterCountInvalid: boolean;\n  invalid: boolean;\n}) => {\n  if (invalid) return 'This is a required field';\n  if (characterCountInvalid)\n    return `${characterCount - maxCharacters} character${characterCount - maxCharacters !== 1 ? 's' : ''} over limit`;\n  return `${maxCharacters - characterCount} character${maxCharacters - characterCount !== 1 ? 's' : ''} remaining`;\n};\n\nexport const TextCountTextarea = () => {\n  const [invalid, setInvalid] = useState(false);\n  const [text, setText] = useState('');\n\n  const characterCount = text.length;\n  const characterCountInvalid = characterCount > maxCharacters;\n  const messageIsError = characterCountInvalid || invalid;\n\n  const message = getMessage({ characterCount, characterCountInvalid, invalid });\n\n  const onReset = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    setInvalid(false);\n    setText('');\n  };\n  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    setInvalid(characterCount === 0);\n  };\n  const onTextChange = (e: ChangeEvent<HTMLInputElement>) => {\n    setInvalid(false);\n    setText(e.target.value);\n  };\n\n  return (\n    <form onReset={onReset} onSubmit={onSubmit}>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer className=\"v-flex-row\">\n          <Textarea<'input'>\n            aria-describedby={`${id}-message`}\n            aria-invalid={characterCountInvalid || invalid}\n            aria-required=\"true\"\n            fixed\n            id={id}\n            name={id}\n            onChange={onTextChange}\n            style={{ blockSize: '130px' }}\n            value={text}\n          />\n        </InputContainer>\n        <UtilityFragment vFlex vFlexRow>\n          <InputMessage\n            aria-atomic={messageIsError}\n            aria-live={messageIsError ? 'assertive' : 'polite'}\n            id={`${id}-message`}\n            role={messageIsError ? 'alert' : undefined}\n          >\n            {messageIsError && <VisaErrorTiny />}\n            {message}\n          </InputMessage>\n        </UtilityFragment>\n      </Utility>\n      <Utility vFlex vFlexRow vGap={8} vMarginTop={16}>\n        <Button type=\"submit\">Submit</Button>\n        <Button colorScheme=\"secondary\" type=\"reset\">\n          Reset\n        </Button>\n      </Utility>\n    </form>\n  );\n};\n"
          },
          "name": "Textarea with fixed height and character counter"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-line inputs",
          "url": {
            "iframe": "components/input/native-row-textarea",
            "github": "apps/workshop/src/examples/components/input/native-row-textarea.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputContainer, Label, Textarea, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'text-area-native-row';\n\nexport const NativeRowTextarea = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer className=\"v-flex-row\">\n        <Textarea aria-required=\"true\" fixed id={id} name={id} rows={3} />\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Textarea with native rows attribute"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Custom inputs",
          "url": {
            "iframe": "components/input/custom-inline-label-input",
            "github": "apps/workshop/src/examples/components/input/custom-inline-label-input.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-custom-inline-label';\n\nexport const CustomInlineLabelInput = () => {\n  return (\n    <Utility vAlignItems=\"start\" vFlex vFlexRow vGap={4}>\n      <Label htmlFor={id} style={{ lineHeight: 'var(--v-input-container-block-size)' }}>\n        Label (required)\n      </Label>\n      <Utility vFlex vFlexCol vGap={4} vFlexGrow>\n        <InputContainer>\n          <Input aria-describedby={`${id}-message`} aria-required=\"true\" id={id} type=\"text\" />\n        </InputContainer>\n        <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Input with inline label and message"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Custom inputs",
          "url": {
            "iframe": "components/input/custom-form-input",
            "github": "apps/workshop/src/examples/components/input/custom-form-input.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { Button, Input, InputContainer, Label, Utility } from '@visa/nova-react';\nimport type { FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'input-form-control';\n\nexport const CustomFormInput = () => {\n  const onSubmit = (event: FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n    const formData = new FormData(event.currentTarget);\n    const query = formData.get(id);\n    alert(`${query} submitted!`);\n  };\n  return (\n    <form onSubmit={onSubmit}>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Input aria-required=\"true\" id={id} name={id} type=\"text\" />\n        </InputContainer>\n      </Utility>\n      <Utility vFlex vFlexRow vGap={8} vMarginTop={16}>\n        <Button type=\"submit\">Submit</Button>\n        <Button colorScheme=\"secondary\" type=\"reset\">\n          Reset\n        </Button>\n      </Utility>\n    </form>\n  );\n};\n"
          },
          "name": "Input with form control"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Custom inputs",
          "url": {
            "iframe": "components/input/cvv-input",
            "github": "apps/workshop/src/examples/components/input/cvv-input.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, Input, InputContainer, InputMessage, Label, Utility } from '@visa/nova-react';\nimport { useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'cvv-input';\n\nconst cvvLength = 3;\n\nexport const CVVInput = () => {\n  const [invalid, setInvalid] = useState(false);\n  const [focused, setFocused] = useState(false);\n\n  const onReset = () => {\n    setInvalid(false);\n  };\n  const onSubmit = (event: FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n    const isValid = event.currentTarget.checkValidity();\n    const formData = new FormData(event.currentTarget);\n    const formDataObject = Object.fromEntries(formData.entries());\n\n    // If valid, alert with CVV\n    if (isValid) alert(`Success!\\nCVV: ${formDataObject['cvv-input']}`);\n    // If invalid, focus on invalid element\n    else (event.currentTarget.querySelector(':invalid') as HTMLInputElement)?.focus();\n\n    setInvalid(!isValid);\n  };\n\n  return (\n    <Utility<'form'> noValidate onReset={onReset} onSubmit={onSubmit} tag=\"form\" vFlex vFlexCol vGap={4}>\n      <Label htmlFor={id}>Security code</Label>\n      <InputContainer>\n        <Input\n          aria-describedby={`${id}-message`}\n          aria-invalid={invalid}\n          aria-required=\"true\"\n          autoComplete=\"cc-csc\"\n          id={id}\n          maxLength={cvvLength}\n          name={id}\n          onBlur={() => setFocused(false)}\n          onFocus={() => setFocused(true)}\n          pattern={`[0-9]{${cvvLength}}`}\n          required\n          type={focused ? 'text' : 'password'}\n        />\n      </InputContainer>\n      {invalid && (\n        <InputMessage id={`${id}-message`}>\n          <VisaErrorTiny />\n          Please choose a valid security code.\n        </InputMessage>\n      )}\n      <Utility vFlex vFlexRow vGap={8} vMarginTop={16}>\n        <Button type=\"submit\">Submit</Button>\n        <Button colorScheme=\"secondary\" type=\"reset\">\n          Reset\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "CVV input"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Custom inputs",
          "url": {
            "iframe": "components/input/reusable",
            "github": "apps/workshop/src/examples/components/input/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import {\n  VisaAccountLow,\n  VisaCheckmarkLow,\n  VisaClearAltTiny,\n  VisaErrorTiny,\n  VisaPasswordHideTiny,\n  VisaPasswordShowTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Input,\n  InputContainer,\n  InputMessage,\n  type InputProperties,\n  Label,\n  Textarea,\n  type TextAreaProperties,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport {\n  type ChangeEvent,\n  type ComponentPropsWithRef,\n  type ElementType,\n  type FocusEvent,\n  type ReactNode,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\n\ntype InheritedProps<ET extends ElementType> = ET extends 'input'\n  ? InputProperties<'input'>\n  : ET extends 'textarea'\n    ? TextAreaProperties<'textarea'>\n    : ComponentPropsWithRef<ET>;\n\n// Nova Input Component Props\nexport type NovaInputProps<ET extends ElementType = 'input'> = InheritedProps<ET> & {\n  blockSize?: string;\n  clearable?: boolean;\n  inline?: boolean;\n  invalid?: boolean;\n  label?: string;\n  maskable?: boolean;\n  message?: string;\n  otp?: boolean;\n  prefix?: string;\n  prefixIcon?: ReactNode;\n  readonly?: boolean;\n  required?: boolean;\n  resizable?: boolean;\n  step?: number;\n  suffix?: string;\n  suffixIcon?: ReactNode;\n  textarea?: boolean;\n};\n\n// Main Nova Input Component\nexport const NovaInput = <ET extends ElementType = 'input'>({\n  blockSize = 'var(--v-input-container-block-size)',\n  clearable = false,\n  disabled = false,\n  id: idProp,\n  inline = false,\n  invalid = false,\n  label = '',\n  maskable = false,\n  message,\n  otp = false,\n  placeholder,\n  prefix,\n  prefixIcon,\n  readonly = false,\n  required = false,\n  resizable = true,\n  step,\n  suffix,\n  suffixIcon,\n  textarea = false,\n  type: typeProp,\n  value: controlledValue,\n  onChange,\n  ...remainingInputProps\n}: NovaInputProps<ET>) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const [internalValue, setInternalValue] = useState('');\n  const [inFocus, setInFocus] = useState(false);\n  const [masked, setMasked] = useState(true);\n\n  const inputRef = useRef<HTMLInputElement>(null);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n  const buttonRef = useRef<HTMLButtonElement>(null);\n\n  // Use controlled value if provided, otherwise use internal state\n  const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n  // Determine the input type\n  const inputType = useMemo(() => {\n    if (typeProp) return typeProp;\n    if (!maskable) return 'text';\n    return masked ? 'password' : 'text';\n  }, [typeProp, maskable, masked]);\n\n  // Calculate aria-describedby\n  const inputDescribedBy = useMemo(() => {\n    const ids: string[] = [];\n    if (message) ids.push(`${id}-message`);\n    if (prefix) ids.push(`${id}-prefix`);\n    if (suffix) ids.push(`${id}-suffix`);\n    return ids.length > 0 ? ids.join(' ') : undefined;\n  }, [message, prefix, suffix, id]);\n\n  const handleInputChange = (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n    const newValue = event.target.value;\n    if (controlledValue === undefined) {\n      setInternalValue(newValue);\n    }\n    onChange?.(event as ChangeEvent<HTMLInputElement>);\n  };\n\n  const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n    const relatedTarget = event.relatedTarget as HTMLElement;\n    if (\n      relatedTarget !== buttonRef.current &&\n      relatedTarget !== inputRef.current &&\n      relatedTarget !== textareaRef.current &&\n      !event.currentTarget.contains(relatedTarget)\n    ) {\n      setInFocus(false);\n    }\n  };\n\n  const handleClear = () => {\n    handleInputChange({ target: { value: '' } } as ChangeEvent<HTMLInputElement | HTMLTextAreaElement>);\n    if (textarea) {\n      textareaRef.current?.focus();\n    } else {\n      inputRef.current?.focus();\n    }\n  };\n\n  const handleToggleMask = () => {\n    setMasked(prev => !prev);\n  };\n\n  const showClearButton = value && value.length > 0 && inFocus && clearable;\n\n  return (\n    <Utility\n      vAlignItems={inline ? 'start' : undefined}\n      vFlex\n      vFlexCol={!inline}\n      vFlexRow={inline}\n      vFlexWrap={inline}\n      vGap={4}\n    >\n      <Label htmlFor={`${id}-input`} style={inline ? { lineHeight: 'var(--v-input-container-block-size)' } : undefined}>\n        {label} {required ? ' (required)' : ''}\n      </Label>\n      <Utility vFlex vFlexCol vFlexGrow vGap={4}>\n        <InputContainer\n          onBlur={handleBlur}\n          onFocus={() => setInFocus(true)}\n          style={otp ? { inlineSize: '160px' } : undefined}\n        >\n          {prefixIcon}\n          {prefix && (\n            <Typography className=\"v-typography-body-2-bold\" id={`${id}-prefix`} tag=\"span\">\n              {prefix}\n            </Typography>\n          )}\n\n          {textarea ? (\n            <Textarea\n              ref={textareaRef}\n              aria-describedby={inputDescribedBy}\n              aria-invalid={invalid}\n              disabled={disabled}\n              fixed={!resizable}\n              id={`${id}-input`}\n              onChange={handleInputChange}\n              placeholder={placeholder}\n              readOnly={readonly}\n              required={required}\n              style={{ blockSize }}\n              value={value}\n              {...remainingInputProps}\n            />\n          ) : (\n            <Input\n              ref={inputRef}\n              aria-describedby={inputDescribedBy}\n              aria-invalid={invalid}\n              disabled={disabled}\n              id={`${id}-input`}\n              onChange={handleInputChange}\n              otp={otp}\n              placeholder={placeholder}\n              readOnly={readonly}\n              required={required}\n              step={step}\n              type={inputType}\n              value={value}\n              {...remainingInputProps}\n            />\n          )}\n\n          {showClearButton && (\n            <Button\n              aria-label=\"clear\"\n              ref={buttonRef}\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={disabled}\n              iconButton\n              onClick={handleClear}\n              subtle\n            >\n              <VisaClearAltTiny />\n            </Button>\n          )}\n\n          {suffix && (\n            <Typography className=\"v-typography-body-2-bold\" id={`${id}-suffix`} tag=\"span\">\n              {suffix}\n            </Typography>\n          )}\n\n          {maskable && (\n            <Button\n              aria-label={masked ? 'show password' : 'hide password'}\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={disabled}\n              iconButton\n              onClick={handleToggleMask}\n            >\n              {masked ? <VisaPasswordShowTiny /> : <VisaPasswordHideTiny />}\n            </Button>\n          )}\n\n          {suffixIcon}\n        </InputContainer>\n\n        {message && (\n          <InputMessage aria-atomic={invalid} aria-live={invalid ? 'assertive' : undefined} id={`${id}-message`}>\n            {invalid && <VisaErrorTiny />}\n            {message}\n          </InputMessage>\n        )}\n      </Utility>\n    </Utility>\n  );\n};\n\n// export default NovaInput;\n\n/* !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  clearable: boolean;\n  disabled: boolean;\n  errorMessage: string;\n  inline: boolean;\n  invalid: boolean;\n  label: string;\n  maskable: boolean;\n  message: string;\n  otp: boolean;\n  placeholder: string;\n  readonly: boolean;\n  required: boolean;\n  showLeadingIcon: boolean;\n  showPrefix: boolean;\n  showTrailingIcon: boolean;\n  showSuffix: boolean;\n}\n\n// Demo Component\nexport const NovaInputDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    clearable: false,\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    inline: false,\n    invalid: false,\n    label: 'Label',\n    maskable: false,\n    message: 'This is optional text that describes the label in more detail.',\n    otp: false,\n    placeholder: '',\n    readonly: false,\n    required: false,\n    showLeadingIcon: false,\n    showPrefix: false,\n    showTrailingIcon: false,\n    showSuffix: false,\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <NovaInput\n        clearable={customizations.clearable}\n        disabled={customizations.disabled}\n        inline={customizations.inline}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        maskable={customizations.maskable}\n        message={customizations.invalid ? customizations.errorMessage : customizations.message}\n        otp={customizations.otp}\n        placeholder={customizations.placeholder || ''}\n        prefix={customizations.showPrefix ? '$' : ''}\n        prefixIcon={customizations.showLeadingIcon ? <VisaAccountLow /> : undefined}\n        readonly={customizations.readonly}\n        required={customizations.required}\n        suffix={customizations.showSuffix ? ' %' : ''}\n        suffixIcon={customizations.showTrailingIcon ? <VisaCheckmarkLow /> : undefined}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <Label>\n                <Checkbox\n                  checked={formValues.clearable}\n                  onChange={e => handleInputChange('clearable', e.target.checked)}\n                />\n                Clearable\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.disabled}\n                  onChange={e => handleInputChange('disabled', e.target.checked)}\n                />\n                Disabled\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.inline} onChange={e => handleInputChange('inline', e.target.checked)} />\n                Inline\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.invalid} onChange={e => handleInputChange('invalid', e.target.checked)} />\n                Invalid\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.maskable}\n                  onChange={e => handleInputChange('maskable', e.target.checked)}\n                />\n                Maskable\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.otp} onChange={e => handleInputChange('otp', e.target.checked)} />\n                OTP\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.readonly}\n                  onChange={e => handleInputChange('readonly', e.target.checked)}\n                />\n                Readonly\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.required}\n                  onChange={e => handleInputChange('required', e.target.checked)}\n                />\n                Required\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.showLeadingIcon}\n                  onChange={e => handleInputChange('showLeadingIcon', e.target.checked)}\n                />\n                Show leading icon\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.showPrefix}\n                  onChange={e => handleInputChange('showPrefix', e.target.checked)}\n                />\n                Show prefix\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.showSuffix}\n                  onChange={e => handleInputChange('showSuffix', e.target.checked)}\n                />\n                Show suffix\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.showTrailingIcon}\n                  onChange={e => handleInputChange('showTrailingIcon', e.target.checked)}\n                />\n                Show trailing icon\n              </Label>\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaInputDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable input"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Input",
          "selector": "<Input />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Text fields that enable users to enter free-form content."
        },
        {
          "order": 2,
          "name": "Inputcontainer",
          "selector": "<InputContainer />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for styling input elements."
        },
        {
          "order": 3,
          "name": "Inputcontrol",
          "selector": "<InputControl />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for icons controlling form elements, such as a dropdown icon for a select element."
        },
        {
          "order": 4,
          "name": "Inputmessage",
          "selector": "<InputMessage />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Message shown beneath input components to provide context or guidance."
        }
      ],
      "properties": [
        {
          "name": "otp",
          "section": "Input",
          "data": {
            "name": "otp",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "one-time pass-code style"
          }
        },
        {
          "name": "tag",
          "section": "Input",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "input",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "surfaceType",
          "section": "Inputcontainer",
          "data": {
            "name": "surfaceType",
            "type": "\"alternate\"",
            "default": "",
            "required": "false",
            "description": "Type of Surface"
          }
        },
        {
          "name": "tag",
          "section": "Inputcontainer",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Inputcontrol",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "colorScheme",
          "section": "Inputmessage",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Inputmessage",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "span",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Inputmessage",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "link",
      "version": "0.0.1",
      "description": "Text-based navigation elements that directs users to another destination.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Standalone links",
          "description": "",
          "order": 1
        },
        {
          "name": "Inline links",
          "description": "",
          "order": 2
        },
        {
          "name": "Links coded as buttons",
          "description": "",
          "order": 3
        },
        {
          "name": "Custom examples",
          "description": "",
          "order": 4
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/default-link",
            "github": "apps/workshop/src/examples/components/link/default-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Link } from '@visa/nova-react';\n\nexport const DefaultLink = () => {\n  return <Link href=\"./link\">Destination label</Link>;\n};\n"
          },
          "name": "Default link"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/leading-icon-link",
            "github": "apps/workshop/src/examples/components/link/leading-icon-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaArrowBackTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const LeadingIconLink = () => {\n  return (\n    <Link href=\"./link\" noUnderline>\n      <VisaArrowBackTiny />\n      Destination label\n    </Link>\n  );\n};\n"
          },
          "name": "Link with leading icon"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/trailing-icon-link",
            "github": "apps/workshop/src/examples/components/link/trailing-icon-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const TrailingIconLink = () => {\n  return (\n    <Link href=\"./link\" noUnderline>\n      Destination label\n      <VisaChevronRightTiny />\n    </Link>\n  );\n};\n"
          },
          "name": "Link with trailing icon"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/alternate-link",
            "github": "apps/workshop/src/examples/components/link/alternate-link.tsx"
          },
          "tags": [
            "alternate",
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const AlternateLink = () => {\n  return (\n    <Link alternate href=\"./link\" noUnderline>\n      Destination label\n      <VisaChevronRightTiny />\n    </Link>\n  );\n};\n"
          },
          "name": "Alternate link with trailing icon"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/new-tab-link",
            "github": "apps/workshop/src/examples/components/link/new-tab-link.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMaximizeTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const NewTabLink = () => {\n  return (\n    <Link\n      aria-label=\"Destination label (opens in a new tab)\"\n      href=\"./link\"\n      noUnderline\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n    >\n      Destination label\n      <VisaMaximizeTiny />\n    </Link>\n  );\n};\n"
          },
          "name": "Link that opens in a new tab"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Standalone links",
          "url": {
            "iframe": "components/link/disabled-link",
            "github": "apps/workshop/src/examples/components/link/disabled-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Link } from '@visa/nova-react';\n\nexport const DisabledLink = () => {\n  return (\n    <Link disabled role=\"link\">\n      Destination label\n    </Link>\n  );\n};\n"
          },
          "name": "Disabled link"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Inline links",
          "url": {
            "iframe": "components/link/inline-link",
            "github": "apps/workshop/src/examples/components/link/inline-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Link, Typography } from '@visa/nova-react';\n\nexport const InlineLink = () => {\n  return (\n    <Typography>\n      This is a sentence with an inline <Link href=\"./link\">destination label</Link>.\n    </Typography>\n  );\n};\n"
          },
          "name": "Inline link"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Inline links",
          "url": {
            "iframe": "components/link/without-underline-link",
            "github": "apps/workshop/src/examples/components/link/without-underline-link.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMaximizeTiny } from '@visa/nova-icons-react';\nimport { Link, Typography } from '@visa/nova-react';\n\nexport const WithoutUnderlineLink = () => {\n  return (\n    <Typography>\n      This is a sentence with an inline{' '}\n      <Link aria-label=\"destination label (opens in a new tab)\" href=\"./link\" noUnderline>\n        destination label\n        <VisaMaximizeTiny />\n      </Link>\n    </Typography>\n  );\n};\n"
          },
          "name": "Inline link with trailing icon"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Links coded as buttons",
          "url": {
            "iframe": "components/link/custom-tag-link",
            "github": "apps/workshop/src/examples/components/link/custom-tag-link.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaDevicePrinterTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const CustomTagLink = () => {\n  return (\n    <Link noUnderline element={<button />}>\n      Print\n      <VisaDevicePrinterTiny />\n    </Link>\n  );\n};\n"
          },
          "name": "Link coded as a button"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Links coded as buttons",
          "url": {
            "iframe": "components/link/disabled-custom-tag-link",
            "github": "apps/workshop/src/examples/components/link/disabled-custom-tag-link.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDevicePrinterTiny } from '@visa/nova-icons-react';\nimport { Link } from '@visa/nova-react';\n\nexport const DisabledCustomTagLink = () => {\n  return (\n    <Link noUnderline element={<button disabled/>}>\n      Print\n      <VisaDevicePrinterTiny />\n    </Link>\n  );\n};\n"
          },
          "name": "Disabled link coded as a button"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Custom examples",
          "url": {
            "iframe": "components/link/react-router-link",
            "github": "apps/workshop/src/examples/components/link/react-router-link.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { Link } from 'react-router-dom';\nimport { Link as VLink } from '@visa/nova-react';\n\nexport const ReactRouterLink = () => {\n  return (\n    <>\n      This <VLink element={<Link to={'./'}>link</Link>} /> goes to this current page.\n    </>\n  );\n};\n"
          },
          "name": "Link uses React Router DOM"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Custom examples",
          "url": {
            "iframe": "components/link/custom-typography-link",
            "github": "apps/workshop/src/examples/components/link/custom-typography-link.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Link, Typography } from '@visa/nova-react';\n\nexport const CustomTypographyLink = () => {\n  return (\n    <Link href=\"./link\" noUnderline>\n      <Typography variant=\"headline-3\">\n        Destination label (headline 3) <VisaChevronRightTiny /> \n      </Typography>\n    </Link>\n  );\n};\n"
          },
          "name": "Link with custom typography"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Link",
          "selector": "<Link />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Text-based navigation elements that directs users to another destination."
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Link",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "disabled",
          "section": "Link",
          "data": {
            "name": "disabled",
            "type": "Booleanish",
            "default": "",
            "required": "false",
            "description": "Disabled"
          }
        },
        {
          "name": "element",
          "section": "Link",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "noUnderline",
          "section": "Link",
          "data": {
            "name": "noUnderline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "No Underline"
          }
        },
        {
          "name": "skipLink",
          "section": "Link",
          "data": {
            "name": "skipLink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Skip Link"
          }
        },
        {
          "name": "tag",
          "section": "Link",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "a",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        }
      ]
    },
    {
      "name": "list-item",
      "version": "0.0.1",
      "description": "Individual containers that can be grouped to create lists in web and mobile apps.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Static list items",
          "description": "",
          "order": 1
        },
        {
          "name": "Clickthrough list items",
          "description": "",
          "order": 2
        },
        {
          "name": "Switch list items",
          "description": "",
          "order": 3
        },
        {
          "name": "Checkbox list items",
          "description": "",
          "order": 4
        },
        {
          "name": "Radio list items",
          "description": "",
          "order": 5
        },
        {
          "name": "Lists",
          "description": "",
          "order": 6
        },
        {
          "name": "Custom lists",
          "description": "",
          "order": 7
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/one-line-list-item",
            "github": "apps/workshop/src/examples/components/list-item/one-line-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const OneLineListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "One-line list item"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/one-line-two-column-list-item",
            "github": "apps/workshop/src/examples/components/list-item/one-line-two-column-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const OneLineTwoColumnListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        vJustifyContent=\"between\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label 1\n          </Typography>\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label 2\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "One-line, two-column list item"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/two-line-list-item",
            "github": "apps/workshop/src/examples/components/list-item/two-line-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const TwoLineListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vFlexCol\n        vGap={2}\n        vJustifyContent=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <Typography variant=\"label\" tag=\"span\">\n            Secondary text\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Two-line list item"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/three-line-list-item",
            "github": "apps/workshop/src/examples/components/list-item/three-line-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const ThreeLineListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vFlexCol\n        vGap={2}\n        vJustifyContent=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <Typography variant=\"label\" tag=\"span\">\n            Secondary text\n          </Typography>\n          <Typography variant=\"label-small\" tag=\"span\">\n            Tertiary text\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Three-line list item"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/leading-icon-list-item",
            "github": "apps/workshop/src/examples/components/list-item/leading-icon-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { GenericInformationLow } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\nimport { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const LeadingIconListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vGap={8}\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <GenericInformationLow style={{ color: 'var(--palette-default-active-subtle)' } as CSSProperties} />\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Leading icon list item"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/leading-icon-with-background-list-item",
            "github": "apps/workshop/src/examples/components/list-item/leading-icon-with-background-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountLow } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\nimport { Typography, Utility, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const LeadingIconWithBackgroundListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vGap={8}\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Utility\n            vFlex\n            vPadding={8}\n            style={{ backgroundColor: 'var(--palette-default-surface-3)', borderRadius: '4px' }}\n          >\n            <VisaAccountLow\n              style={\n                {\n                  color: 'var(--palette-default-text-subtle)',\n                  '--v-icon-primary': 'currentColor',\n                  '--v-icon-secondary': 'currentColor',\n                } as CSSProperties\n              }\n            />\n          </Utility>\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Leading icon with background list item"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/leading-image-list-item",
            "github": "apps/workshop/src/examples/components/list-item/leading-image-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar, Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\nconst user = 'Alex Miller';\n\nexport const LeadingImageListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vGap={8}\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Avatar<'img'> alt={user} tag=\"img\" src={BASE_URL + '/alex-miller-stock.png'} />\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Leading image list item"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/leading-card-art-list-item",
            "github": "apps/workshop/src/examples/components/list-item/leading-card-art-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, VisaLogo, Utility } from '@visa/nova-react';\n\nexport const LeadingCardArtListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vGap={8}\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Utility\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"center\"\n            style={{\n              backgroundColor: 'var(--palette-default-active-pressed)',\n              borderRadius: '2px',\n              inlineSize: '40px',\n              blockSize: '25px',\n            }}\n          >\n            <VisaLogo aria-label=\"Visa\" style={{ fill: 'white', height: '10px', width: '30px' }} />\n          </Utility>\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Leading card art list item"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/indicator-line-list-item",
            "github": "apps/workshop/src/examples/components/list-item/indicator-line-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, Utility, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const IndicatorLineListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingLeft={0}\n        vPaddingRight={8}\n        vPaddingVertical={6}\n        vFlex\n        vGap={3}\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Utility\n            style={{\n              backgroundColor: 'var(--palette-default-active)',\n              inlineSize: '5px',\n              blockSize: '56px',\n              borderRadius: '10px',\n            }}\n          />\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Indicator line list item"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/trailing-icon-list-item",
            "github": "apps/workshop/src/examples/components/list-item/trailing-icon-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { GenericInformationLow } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\nimport { Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\nexport const TrailingIconListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        vJustifyContent=\"between\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <GenericInformationLow style={{ color: 'var(--palette-default-active-subtle)' } as CSSProperties} />\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Trailing icon list item"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/trailing-icon-with-background-list-item",
            "github": "apps/workshop/src/examples/components/list-item/trailing-icon-with-background-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountLow } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\nimport { Typography, UtilityFragment, Surface, Utility } from '@visa/nova-react';\n\nexport const TrailingIconWithBackgroundListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        vJustifyContent=\"between\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <Utility\n            vFlex\n            vPadding={8}\n            style={{ backgroundColor: 'var(--palette-default-surface-3)', borderRadius: '4px' }}\n          >\n            <VisaAccountLow\n              style={\n                {\n                  color: 'var(--palette-default-text-subtle)',\n                  '--v-icon-primary': 'currentColor',\n                  '--v-icon-secondary': 'currentColor',\n                } as CSSProperties\n              }\n            />\n          </Utility>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Trailing icon with background list item"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/trailing-image-list-item",
            "github": "apps/workshop/src/examples/components/list-item/trailing-image-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar, Typography, UtilityFragment, Surface } from '@visa/nova-react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\nconst user = 'Alex Miller';\n\nexport const TrailingImageListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vJustifyContent=\"between\"\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <Avatar<'img'> alt={user} tag=\"img\" src={BASE_URL + '/alex-miller-stock.png'} />\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Trailing image list item"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Static list items",
          "url": {
            "iframe": "components/list-item/trailing-card-art-list-item",
            "github": "apps/workshop/src/examples/components/list-item/trailing-card-art-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, Utility, VisaLogo } from '@visa/nova-react';\n\nexport const TrailingCardArtListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vJustifyContent=\"between\"\n        vAlignItems=\"center\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <Typography variant=\"label-large\" tag=\"span\">\n            Item label\n          </Typography>\n          <Utility\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"center\"\n            style={{\n              backgroundColor: 'var(--palette-default-active-pressed)',\n              borderRadius: '2px',\n              inlineSize: '40px',\n              blockSize: '25px',\n            }}\n          >\n            <VisaLogo aria-label=\"Visa\" style={{ fill: 'white', height: '10px', width: '30px' }} />\n          </Utility>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Trailing card art list item"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/default-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/default-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Surface, Button } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const DefaultClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={\n              {\n                color: 'var(--palette-default-text)',\n                '--v-button-default-border-radius': '0px',\n                minBlockSize: '64px',\n              } as CSSProperties\n            }\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\">\n                  <Typography variant=\"label-large\" tag=\"span\">\n                    Item label\n                  </Typography>\n                  <VisaChevronRightTiny style={{ color: 'var(--palette-default-active)' }} />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Default clickthrough list item"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/disabled-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Surface, Button } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const DisabledClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={{ '--v-button-default-border-radius': '0px', minBlockSize: '64px' } as CSSProperties}\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\" tabIndex={-1} aria-disabled=\"true\" role=\"link\">\n                  <Typography variant=\"label-large\" tag=\"span\">\n                    Item label\n                  </Typography>\n                  <VisaChevronRightTiny />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled clickthrough list item"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/disabled-leading-image-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-leading-image-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Avatar, Typography, Utility, UtilityFragment, Surface, Button } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n/// This is the base url for where your site is deployed. `import.meta.env.BASE_URL` is the environment variable used to import the base url for Vite. Change this import to match your build tool's base url.\nconst BASE_URL = import.meta.env.BASE_URL;\nconst user = 'Alex Miller';\n\nexport const DisabledLeadingImageClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={{ '--v-button-default-border-radius': '0px', minBlockSize: '64px' } as CSSProperties}\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\" tabIndex={-1} aria-disabled=\"true\" role=\"link\">\n                  <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                    <Avatar<'img'>\n                      alt={user}\n                      tag=\"img\"\n                      src={BASE_URL + '/alex-miller-stock.png'}\n                      style={{ '--v-avatar-size': '48px' } as CSSProperties}\n                    />\n                    <Typography variant=\"label-large\" tag=\"span\">\n                      Item label\n                    </Typography>\n                  </Utility>\n                  <VisaChevronRightTiny />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled leading image clickthrough list item"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/disabled-leading-icon-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-leading-icon-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { GenericSecurityProtectionLow, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, Utility, UtilityFragment, Surface, Button } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const DisabledLeadingIconClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={{ '--v-button-default-border-radius': '0px', minBlockSize: '64px' } as CSSProperties}\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\" tabIndex={-1} aria-disabled=\"true\" role=\"link\">\n                  <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                    <GenericSecurityProtectionLow\n                      style={{ '--v-icon-height': '24px', '--v-icon-width': '24px' } as CSSProperties}\n                    />\n                    <Typography variant=\"label-large\" tag=\"span\">\n                      Item label\n                    </Typography>\n                  </Utility>\n                  <VisaChevronRightTiny />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled leading icon clickthrough list item"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/disabled-card-art-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-card-art-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, Utility, UtilityFragment, Surface, Button, VisaLogo } from '@visa/nova-react';\n\nexport const DisabledCardArtClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={{ minBlockSize: '64px' }}\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\" tabIndex={-1} aria-disabled=\"true\" role=\"link\">\n                  <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                    <Utility\n                      vFlex\n                      vAlignItems=\"center\"\n                      vJustifyContent=\"center\"\n                      style={{\n                        backgroundColor: 'var(--palette-default-active-pressed)',\n                        opacity: '0.3',\n                        mixBlendMode: 'luminosity',\n                        borderRadius: '2px',\n                        inlineSize: '40px',\n                        blockSize: '25px',\n                      }}\n                    >\n                      <VisaLogo aria-label=\"Visa\" style={{ fill: 'white', height: '10px', width: '30px' }} />\n                    </Utility>\n                    <Typography variant=\"label-large\" tag=\"span\">\n                      Item label\n                    </Typography>\n                  </Utility>\n                  <VisaChevronRightTiny />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled card art clickthrough list item"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Clickthrough list items",
          "url": {
            "iframe": "components/list-item/disabled-card-art-with-number-clickthrough-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-card-art-with-number-clickthrough-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, Utility, UtilityFragment, Surface, Button, VisaLogo } from '@visa/nova-react';\n\nexport const DisabledCardArtWithNumberClickthroughListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            vPaddingLeft={8}\n            vPaddingRight={4}\n            vPaddingVertical={6}\n            style={{ minBlockSize: '64px' }}\n          >\n            <Button\n              colorScheme=\"tertiary\"\n              element={\n                <a href=\"./list-item\" tabIndex={-1} aria-disabled=\"true\" role=\"link\">\n                  <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                    <Utility vFlex vAlignItems=\"center\" vGap={4}>\n                      <Utility\n                        vFlex\n                        vAlignItems=\"center\"\n                        vJustifyContent=\"center\"\n                        style={{\n                          backgroundColor: 'var(--palette-default-active-pressed)',\n                          opacity: '0.3',\n                          mixBlendMode: 'luminosity',\n                          borderRadius: '2px',\n                          inlineSize: '40px',\n                          blockSize: '25px',\n                        }}\n                      >\n                        <VisaLogo aria-label=\"Visa\" style={{ fill: 'white', height: '10px', width: '30px' }} />\n                      </Utility>\n                      <Typography variant=\"label\" tag=\"span\">\n                        •••• 1234\n                      </Typography>\n                    </Utility>\n                    <Typography variant=\"label-large\" tag=\"span\">\n                      Item label\n                    </Typography>\n                  </Utility>\n                  <VisaChevronRightTiny />\n                </a>\n              }\n            />\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled card art with number clickthrough list item"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Switch list items",
          "url": {
            "iframe": "components/list-item/default-switch-list-item",
            "github": "apps/workshop/src/examples/components/list-item/default-switch-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { UtilityFragment, Typography, Surface, Switch, SwitchLabel } from '@visa/nova-react';\n\nconst id = 'default-switch-list-item';\n\nexport const DefaultSwitchListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        vJustifyContent=\"between\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <SwitchLabel htmlFor={`${id}-switch`}>\n            <Typography variant=\"label-large\" tag=\"span\">\n              Item label\n            </Typography>\n          </SwitchLabel>\n          <Switch id={`${id}-switch`} name=\"default-switch-list-item\" />\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Default switch list item"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Switch list items",
          "url": {
            "iframe": "components/list-item/disabled-switch-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-switch-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { UtilityFragment, Typography, Surface, Switch, SwitchLabel } from '@visa/nova-react';\n\nconst id = 'disabled-switch-list-item';\n\nexport const DisabledSwitchListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment\n        vPaddingHorizontal={8}\n        vPaddingVertical={6}\n        vFlex\n        vAlignItems=\"center\"\n        vJustifyContent=\"between\"\n        style={{ minBlockSize: '64px' }}\n      >\n        <Surface tag=\"li\">\n          <SwitchLabel htmlFor={`${id}-switch`}>\n            <Typography variant=\"label-large\" tag=\"span\">\n              Item label\n            </Typography>\n          </SwitchLabel>\n          <Switch disabled id={`${id}-switch`} name=\"disabled-switch-list-item\" />\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled switch list item"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox list items",
          "url": {
            "iframe": "components/list-item/default-checkbox-list-item",
            "github": "apps/workshop/src/examples/components/list-item/default-checkbox-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, Label, Checkbox } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-checkbox-list-item';\n\nexport const DefaultCheckboxListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vPaddingHorizontal={8}\n            vPaddingVertical={6}\n            vFlex\n            vAlignItems={'center'}\n            vGap={8}\n            className=\"v-action v-action-secondary\"\n          >\n            <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={id}>\n              <Checkbox id={id} name={id} style={{ '--v-checkbox-glow-offset': '0' } as CSSProperties} />\n              <Typography variant=\"label-large\" tag=\"span\">\n                Item label\n              </Typography>\n            </Label>\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Default checkbox list item"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Checkbox list items",
          "url": {
            "iframe": "components/list-item/disabled-checkbox-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-checkbox-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, Label, Checkbox } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-checkbox-list-item';\n\nexport const DisabledCheckboxListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vPaddingHorizontal={8}\n            vPaddingVertical={6}\n            vFlex\n            vAlignItems={'center'}\n            vGap={8}\n            className=\"v-action v-action-secondary\"\n          >\n            <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={id}>\n              <Checkbox disabled id={id} name={id} style={{ '--v-checkbox-glow-offset': '0' } as CSSProperties} />\n              <Typography variant=\"label-large\" tag=\"span\">\n                Item label\n              </Typography>\n            </Label>\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled checkbox list item"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Radio list items",
          "url": {
            "iframe": "components/list-item/default-radio-list-item",
            "github": "apps/workshop/src/examples/components/list-item/default-radio-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, Label, Radio } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-radio-list-item';\n\nexport const DefaultRadioListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vPaddingHorizontal={8}\n            vPaddingVertical={6}\n            vFlex\n            vAlignItems={'center'}\n            vGap={8}\n            className=\"v-action v-action-secondary\"\n          >\n            <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={id}>\n              <Radio id={id} name={id} style={{ '--v-radio-glow-offset': '0' } as CSSProperties} />\n              <Typography variant=\"label-large\" tag=\"span\">\n                Item label\n              </Typography>\n            </Label>\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Default radio list item"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Radio list items",
          "url": {
            "iframe": "components/list-item/disabled-radio-list-item",
            "github": "apps/workshop/src/examples/components/list-item/disabled-radio-list-item.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, Label, Radio } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-radio-list-item';\n\nexport const DisabledRadioListItem = () => {\n  return (\n    <ul style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vPadding={0}>\n        <Surface tag=\"li\">\n          <UtilityFragment\n            vPaddingHorizontal={8}\n            vPaddingVertical={6}\n            vFlex\n            vAlignItems={'center'}\n            vGap={8}\n            className=\"v-action v-action-secondary\"\n          >\n            <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={id}>\n              <Radio disabled id={id} name={id} style={{ '--v-radio-glow-offset': '0' } as CSSProperties} />\n              <Typography variant=\"label-large\" tag=\"span\">\n                Item label\n              </Typography>\n            </Label>\n          </UtilityFragment>\n        </Surface>\n      </UtilityFragment>\n    </ul>\n  );\n};\n"
          },
          "name": "Disabled radio list item"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/default-list",
            "github": "apps/workshop/src/examples/components/list-item/default-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, ContentCard } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: 'item-2', label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: 'item-3', label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: 'item-4', label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const DefaultList = () => {\n  return (\n    <UtilityFragment vPadding={4}>\n      <ContentCard\n        style={\n          {\n            maxInlineSize: '343px',\n            '--v-content-card-border': '0px',\n            '--v-content-card-border-radius': '8px',\n          } as CSSProperties\n        }\n        tag=\"ul\"\n      >\n        {items.map(item => (\n          <UtilityFragment\n            key={item.id}\n            vPaddingHorizontal={8}\n            vPaddingVertical={6}\n            vFlex\n            vAlignItems=\"center\"\n            vJustifyContent=\"between\"\n            style={{ minBlockSize: '64px' }}\n          >\n            <Surface tag=\"li\">\n              <Typography variant=\"label-large\" tag=\"span\">\n                {item.label1}\n              </Typography>\n              <Typography variant=\"label-large\" tag=\"span\">\n                {item.label2}\n              </Typography>\n            </Surface>\n          </UtilityFragment>\n        ))}\n      </ContentCard>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Default list"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/default-list-with-dividers",
            "github": "apps/workshop/src/examples/components/list-item/default-list-with-dividers.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, ContentCard, Divider } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: 'item-2', label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: 'item-3', label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: 'item-4', label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const DefaultListWithDividers = () => {\n  return (\n    <UtilityFragment vPadding={4}>\n      <ContentCard\n        style={\n          {\n            maxInlineSize: '343px',\n            '--v-content-card-border': '0px',\n            '--v-content-card-border-radius': '8px',\n          } as CSSProperties\n        }\n        tag=\"ul\"\n      >\n        {items.map((item, index) => (\n          <li key={item.id}>\n            <UtilityFragment\n              vPaddingHorizontal={8}\n              vPaddingVertical={6}\n              vFlex\n              vAlignItems=\"center\"\n              vJustifyContent=\"between\"\n              style={{ minBlockSize: '64px' }}\n            >\n              <Surface>\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label1}\n                </Typography>\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label2}\n                </Typography>\n              </Surface>\n            </UtilityFragment>\n            {index < items.length - 1 && <Divider dividerType=\"decorative\" />}\n          </li>\n        ))}\n      </ContentCard>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Default list with dividers"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/default-list-with-title",
            "github": "apps/workshop/src/examples/components/list-item/default-list-with-title.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, UtilityFragment, Surface, ContentCard } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: 'item-2', label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: 'item-3', label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: 'item-4', label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const DefaultListWithTitle = () => {\n  return (\n    <section aria-label=\"List title\" style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vMarginBottom={6}>\n        <Typography variant=\"label\" tag=\"span\">\n          List title\n        </Typography>\n      </UtilityFragment>\n      <UtilityFragment vPadding={4}>\n        <ContentCard\n          style={\n            {\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {items.map(item => (\n            <UtilityFragment\n              key={item.id}\n              vPaddingHorizontal={8}\n              vPaddingVertical={6}\n              vFlex\n              vAlignItems=\"center\"\n              vJustifyContent=\"between\"\n              style={{ minBlockSize: '64px' }}\n            >\n              <Surface tag=\"li\">\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label1}\n                </Typography>\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label2}\n                </Typography>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </section>\n  );\n};\n"
          },
          "name": "Default list with title"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/default-list-with-section-title-and-hyperlink",
            "github": "apps/workshop/src/examples/components/list-item/default-list-with-section-title-and-hyperlink.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Utility, Link, Surface, ContentCard } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: 'item-2', label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: 'item-3', label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: 'item-4', label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const DefaultListWithSectionTitleAndHyperlink = () => {\n  return (\n    <section aria-label=\"Section title\" style={{ maxInlineSize: '343px' }}>\n      <Utility vFlex vMarginBottom={6} vAlignItems=\"center\" vJustifyContent=\"between\">\n        <Typography variant=\"label\" tag=\"span\">\n          Section title\n        </Typography>\n        <Link href=\"./list-item\" noUnderline>\n          <Typography variant=\"label\" tag=\"span\">\n            Hyperlink\n          </Typography>\n          <VisaChevronRightTiny />\n        </Link>\n      </Utility>\n      <UtilityFragment vPadding={4}>\n        <ContentCard\n          style={\n            {\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {items.map(item => (\n            <UtilityFragment\n              key={item.id}\n              vPaddingHorizontal={8}\n              vPaddingVertical={6}\n              vFlex\n              vAlignItems=\"center\"\n              vJustifyContent=\"between\"\n              style={{ minBlockSize: '64px' }}\n            >\n              <Surface tag=\"li\">\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label1}\n                </Typography>\n                <Typography variant=\"label-large\" tag=\"span\">\n                  {item.label2}\n                </Typography>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </section>\n  );\n};\n"
          },
          "name": "Default list with section title and hyperlink"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/clickthrough-list",
            "github": "apps/workshop/src/examples/components/list-item/clickthrough-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Surface, ContentCard, Button } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', text: 'Item A label', href: './list-item' },\n  { id: 'item-2', text: 'Item B label', href: './list-item' },\n  { id: 'item-3', text: 'Item C label', href: './list-item' },\n  { id: 'item-4', text: 'Item D label', href: './list-item' },\n];\n\nexport const ClickthroughList = () => {\n  return (\n    <UtilityFragment vPadding={4}>\n      <ContentCard\n        style={\n          {\n            maxInlineSize: '343px',\n            '--v-content-card-border': '0px',\n            '--v-content-card-border-radius': '8px',\n          } as CSSProperties\n        }\n        tag=\"ul\"\n      >\n        {items.map(item => (\n          <UtilityFragment key={item.id} vPadding={0}>\n            <Surface tag=\"li\">\n              <UtilityFragment\n                vFlex\n                vAlignItems=\"center\"\n                vJustifyContent=\"between\"\n                vPaddingLeft={8}\n                vPaddingRight={4}\n                vPaddingVertical={6}\n                style={\n                  {\n                    color: 'var(--palette-default-text)',\n                    '--v-button-default-border-radius': '0px',\n                    minBlockSize: '64px',\n                  } as CSSProperties\n                }\n              >\n                <Button\n                  colorScheme=\"tertiary\"\n                  element={\n                    <a href={item.href}>\n                      <Typography variant=\"label-large\" tag=\"span\">\n                        {item.text}\n                      </Typography>\n                      <VisaChevronRightTiny style={{ color: 'var(--palette-default-active)' }} />\n                    </a>\n                  }\n                />\n              </UtilityFragment>\n            </Surface>\n          </UtilityFragment>\n        ))}\n      </ContentCard>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Clickthrough list"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/radio-list",
            "github": "apps/workshop/src/examples/components/list-item/radio-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, Utility, UtilityFragment, Surface, Label, ContentCard, Radio } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'radio-list';\n\nconst options = [\n  { id: `${id}-1`, label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: `${id}-2`, label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: `${id}-3`, label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: `${id}-4`, label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const RadioList = () => {\n  return (\n    <fieldset aria-label=\"Section title\" style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vMarginBottom={6}>\n        <Label id={`${id}-legend`} tag=\"legend\">\n          Section title\n        </Label>\n      </UtilityFragment>\n      <UtilityFragment vPadding={4} vFlex vFlexCol vGap={4} vMargin={0}>\n        <ContentCard\n          style={\n            {\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {options.map(option => (\n            <UtilityFragment key={option.id} vPadding={0}>\n              <Surface tag=\"li\">\n                <UtilityFragment\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={6}\n                  vFlex\n                  vAlignItems={'center'}\n                  vJustifyContent=\"between\"\n                  vGap={8}\n                  className=\"v-action v-action-secondary\"\n                >\n                  <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={option.id}>\n                    <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                      <Radio id={option.id} name={id} style={{ '--v-radio-glow-offset': '0' } as CSSProperties} />\n                      <Typography variant=\"label-large\" tag=\"span\">\n                        {option.label1}\n                      </Typography>\n                    </Utility>\n                    <Typography variant=\"label-large\">{option.label2}</Typography>\n                  </Label>\n                </UtilityFragment>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Radio list"
        },
        {
          "description": "",
          "order": 32,
          "libraryId": null,
          "componentId": null,
          "section": "Lists",
          "url": {
            "iframe": "components/list-item/checkbox-list",
            "github": "apps/workshop/src/examples/components/list-item/checkbox-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography, Utility, UtilityFragment, Surface, Label, ContentCard, Checkbox } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'checkbox-list';\n\nconst options = [\n  { id: `${id}-1`, label1: 'Item A label 1', label2: 'Item A label 2' },\n  { id: `${id}-2`, label1: 'Item B label 1', label2: 'Item B label 2' },\n  { id: `${id}-3`, label1: 'Item C label 1', label2: 'Item C label 2' },\n  { id: `${id}-4`, label1: 'Item D label 1', label2: 'Item D label 2' },\n];\n\nexport const CheckboxList = () => {\n  return (\n    <fieldset aria-label=\"Section title\" style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vMarginBottom={6}>\n        <Label id={`${id}-legend`} tag=\"legend\">\n          Section title\n        </Label>\n      </UtilityFragment>\n      <UtilityFragment vPadding={4} vFlex vFlexCol vGap={4} vMargin={0}>\n        <ContentCard\n          style={\n            {\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {options.map(option => (\n            <UtilityFragment key={option.id} vPadding={0}>\n              <Surface tag=\"li\">\n                <UtilityFragment\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={6}\n                  vFlex\n                  vAlignItems={'center'}\n                  vJustifyContent=\"between\"\n                  vGap={8}\n                  className=\"v-action v-action-secondary\"\n                >\n                  <Label style={{ border: 'unset', minBlockSize: '64px', inlineSize: '100%' }} htmlFor={option.id}>\n                    <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                      <Checkbox id={option.id} name={id} style={{ '--v-checkbox-glow-offset': '0' } as CSSProperties} />\n                      <Typography variant=\"label-large\" tag=\"span\">\n                        {option.label1}\n                      </Typography>\n                    </Utility>\n                    <Typography variant=\"label-large\">{option.label2}</Typography>\n                  </Label>\n                </UtilityFragment>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Checkbox list"
        },
        {
          "description": "",
          "order": 33,
          "libraryId": null,
          "componentId": null,
          "section": "Custom lists",
          "url": {
            "iframe": "components/list-item/account-clickthrough-list",
            "github": "apps/workshop/src/examples/components/list-item/account-clickthrough-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Surface, ContentCard, Button, Utility, VisaLogo } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', overline: '•••• 1111', href: './list-item', color: '#18385C' },\n  { id: 'item-2', overline: '•••• 2222', href: './list-item', color: '#308342' },\n  { id: 'item-3', overline: '•••• 3333', href: './list-item', color: '#A6304B' },\n  { id: 'item-4', overline: '•••• 4444', href: './list-item', color: '#1569CF' },\n];\n\nexport const AccountClickthroughList = () => {\n  return (\n    <section aria-label=\"List title\" style={{ maxInlineSize: '343px' }}>\n      <UtilityFragment vMarginBottom={6}>\n        <Typography variant=\"label\" tag=\"span\">\n          Accounts\n        </Typography>\n      </UtilityFragment>\n      <UtilityFragment vPadding={4}>\n        <ContentCard\n          style={\n            {\n              maxInlineSize: '343px',\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {items.map(item => (\n            <UtilityFragment key={item.id} vPadding={0}>\n              <Surface tag=\"li\">\n                <UtilityFragment\n                  vFlex\n                  vAlignItems=\"center\"\n                  vJustifyContent=\"between\"\n                  vPaddingLeft={0}\n                  vPaddingRight={4}\n                  vPaddingVertical={6}\n                  style={\n                    {\n                      color: 'var(--palette-default-text)',\n                      '--v-button-default-border-radius': '0px',\n                      minBlockSize: '64px',\n                    } as CSSProperties\n                  }\n                >\n                  <Button\n                    colorScheme=\"tertiary\"\n                    element={\n                      <a href={item.href}>\n                        <Utility vFlex vGap={3}>\n                          <Utility\n                            style={{\n                              backgroundColor: `${item.color}`,\n                              inlineSize: '5px',\n                              blockSize: '56px',\n                              borderRadius: '10px',\n                            }}\n                          />\n                          <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                            <Utility\n                              vFlex\n                              vAlignItems=\"center\"\n                              vJustifyContent=\"center\"\n                              style={{\n                                backgroundColor: `${item.color}`,\n                                borderRadius: '4px',\n                                inlineSize: '40px',\n                                blockSize: '25px',\n                              }}\n                            >\n                              <VisaLogo aria-label=\"Visa\" style={{ fill: 'white', height: '10px', width: '30px' }} />\n                            </Utility>\n                            <Utility vFlex vFlexCol style={{ color: 'var(--palette-default-text)' }}>\n                              <Typography variant=\"overline\">{item.overline}</Typography>\n                              <Typography variant=\"label\">Digital Bank card</Typography>\n                            </Utility>\n                          </Utility>\n                        </Utility>\n                        <Utility vFlex vAlignItems=\"center\" vGap={8}>\n                          <Typography variant=\"subtitle-3\" tag=\"span\">\n                            $1,234.56\n                          </Typography>\n                          <VisaChevronRightTiny style={{ color: 'var(--palette-default-active)' }} />\n                        </Utility>\n                      </a>\n                    }\n                  />\n                </UtilityFragment>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </section>\n  );\n};\n"
          },
          "name": "Account clickthrough list"
        },
        {
          "description": "",
          "order": 34,
          "libraryId": null,
          "componentId": null,
          "section": "Custom lists",
          "url": {
            "iframe": "components/list-item/transactions-list",
            "github": "apps/workshop/src/examples/components/list-item/transactions-list.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Typography, UtilityFragment, Utility, Link, Surface, ContentCard, Avatar } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst items = [\n  { id: 'item-1', merchantName: 'Merchant name' },\n  { id: 'item-2', merchantName: 'Merchant name' },\n  { id: 'item-3', merchantName: 'Merchant name' },\n  { id: 'item-4', merchantName: 'Merchant name' },\n];\n\nexport const TransactionsList = () => {\n  return (\n    <section aria-label=\"Transactions\" style={{ maxInlineSize: '343px' }}>\n      <Utility vFlex vMarginBottom={6} vAlignItems=\"center\" vJustifyContent=\"between\">\n        <Typography variant=\"label\" tag=\"span\">\n          Transactions\n        </Typography>\n        <Link href=\"./list-item\" noUnderline>\n          <Typography variant=\"label\" tag=\"span\">\n            See more\n          </Typography>\n          <VisaChevronRightTiny />\n        </Link>\n      </Utility>\n      <UtilityFragment vPadding={4}>\n        <ContentCard\n          style={\n            {\n              '--v-content-card-border': '0px',\n              '--v-content-card-border-radius': '8px',\n            } as CSSProperties\n          }\n          tag=\"ul\"\n        >\n          {items.map(item => (\n            <UtilityFragment\n              key={item.id}\n              vPaddingHorizontal={8}\n              vPaddingVertical={6}\n              vFlex\n              vAlignItems=\"center\"\n              vJustifyContent=\"between\"\n              style={{ minBlockSize: '64px' }}\n            >\n              <Surface tag=\"li\">\n                <Utility vFlex vGap={8} vAlignItems=\"center\">\n                  <Avatar role=\"img\" aria-label=\"Merchant Name\">\n                    MN\n                  </Avatar>\n                  <Typography variant=\"body-3\" tag=\"span\">\n                    {item.merchantName}\n                  </Typography>\n                </Utility>\n                <Utility vFlex vFlexCol style={{ textAlign: 'end' }}>\n                  <Typography variant=\"subtitle-2\" tag=\"span\">\n                    - $14.57\n                  </Typography>\n                  <Typography variant=\"label\" tag=\"span\" colorScheme=\"subtle\">\n                    $1,234.56\n                  </Typography>\n                </Utility>\n              </Surface>\n            </UtilityFragment>\n          ))}\n        </ContentCard>\n      </UtilityFragment>\n    </section>\n  );\n};\n"
          },
          "name": "Transactions list"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "button",
          "type": "related",
          "selector": "<Button />",
          "description": ""
        },
        {
          "order": 2,
          "name": "checkbox",
          "type": "related",
          "selector": "<Checkbox />",
          "description": ""
        },
        {
          "order": 3,
          "name": "radio",
          "type": "related",
          "selector": "<Radio />",
          "description": ""
        },
        {
          "order": 4,
          "name": "switch",
          "type": "related",
          "selector": "<Switch />",
          "description": ""
        }
      ],
      "properties": []
    },
    {
      "name": "listbox",
      "version": "0.0.1",
      "description": "Container that displays a list of items available for selection.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Single-select listboxes",
          "description": "",
          "order": 1
        },
        {
          "name": "Multi-select listboxes",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom listboxes",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/default-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/default-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const DefaultSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-options`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Default single-select listbox"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/inline-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/inline-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'inline-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const InlineSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-options`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n      <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Single-select listbox with inline message"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/selected-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/selected-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'selected-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const SelectedSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio\n                className=\"v-flex-shrink-0\"\n                defaultChecked={index === 1}\n                id={`${id}-option-${index}`}\n                name={`${id}-option-${index}`}\n              />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Single-select listbox with selected item"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/resize-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/resize-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'resize-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ResizeSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-option-${index}`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Single-select listbox with resize property"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/error-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/error-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputMessage, Label, Listbox, ListboxContainer, ListboxItem, Radio, Utility } from '@visa/nova-react';\nimport { useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ErrorSingleListbox = () => {\n  const [selectedIndex, setSelectedIndex] = useState<number>(-1);\n  const [invalid, setInvalid] = useState(false);\n\n  const onReset = (event: FormEvent) => {\n    event.preventDefault();\n    setInvalid(false);\n    setSelectedIndex(-1);\n  };\n\n  const onSubmit = (event: FormEvent) => {\n    event.preventDefault();\n    setInvalid(selectedIndex === -1);\n  };\n\n  return (\n    <form onReset={onReset} onSubmit={onSubmit}>\n      <fieldset aria-invalid={invalid}>\n        <Label id={`${id}-legend`} tag=\"legend\">\n          Label (required)\n        </Label>\n        <ListboxContainer error={invalid}>\n          <Listbox id={id} scroll tag=\"div\">\n            {options.map((option, index) => (\n              <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n                <Radio\n                  checked={selectedIndex === index}\n                  className=\"v-flex-shrink-0\"\n                  id={`${id}-option-${index}`}\n                  name={`${id}-options`}\n                  onChange={() => setSelectedIndex(index)}\n                />\n                <Label tag=\"span\">{option}</Label>\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </ListboxContainer>\n        {invalid && (\n          <InputMessage id={`${id}-message`}>\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </fieldset>\n\n      <Utility vFlex vFlexRow vGap={8}>\n        <Utility element={<Button type=\"submit\" />} vMarginTop={8}>\n          Submit\n        </Utility>\n        <Utility element={<Button colorScheme=\"secondary\" type=\"reset\" />} vMarginTop={8}>\n          Reset\n        </Utility>\n      </Utility>\n    </form>\n  );\n};\n"
          },
          "name": "Single-select listbox with error"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/disabled-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/disabled-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const DisabledSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer disabled>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio className=\"v-flex-shrink-0\" disabled id={`${id}-option-${index}`} name={`${id}-options`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Disabled single-select listbox"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select listboxes",
          "url": {
            "iframe": "components/listbox/item-disabled-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/item-disabled-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, Radio } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'item-disabled-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ItemDisabledSingleListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Radio\n                className=\"v-flex-shrink-0\"\n                disabled={index === 1}\n                id={`${id}-option-${index}`}\n                name={`${id}-options`}\n              />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Single-select listbox with disabled item"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/default-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/default-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const DefaultMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-option-${index}`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Default multi-select listbox"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/inline-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/inline-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, InputMessage, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'inline-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const InlineMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-option-${index}`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n      <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Multi-select listbox with inline message"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/selected-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/selected-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'selected-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const SelectedMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox\n                className=\"v-flex-shrink-0\"\n                defaultChecked={index === 1}\n                id={`${id}-option-${index}`}\n                name={`${id}-option-${index}`}\n              />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Multi-select listbox with selected item"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/resize-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/resize-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'resize-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ResizeMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-option-${index}`} />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Multi-select listbox with resize property"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/error-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/error-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n} from '@visa/nova-react';\nimport { useState, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ErrorMultiListbox = () => {\n  const [selectedIndexes, setSelectedIndexes] = useState<Record<number, boolean>>({});\n  const [invalid, setInvalid] = useState(false);\n\n  const onSelectionChange = (e: FormEvent<HTMLInputElement>, index: number) => {\n    const newSelectedIndexes = { ...selectedIndexes };\n    newSelectedIndexes[index] = e.currentTarget.checked;\n    setSelectedIndexes(newSelectedIndexes);\n  };\n\n  const onReset = (event: FormEvent) => {\n    event.preventDefault();\n    setInvalid(false);\n    setSelectedIndexes({});\n  };\n\n  const onSubmit = (event: FormEvent) => {\n    event.preventDefault();\n    // If there isn't a card selected, set invalid to true\n    const invalid = !Object.values(selectedIndexes).some(selectedCard => selectedCard);\n    setInvalid(invalid);\n  };\n\n  return (\n    <form onSubmit={onSubmit} onReset={onReset}>\n      <fieldset aria-invalid={invalid}>\n        <Label id={`${id}-legend`} tag=\"legend\">\n          Label (required)\n        </Label>\n        <ListboxContainer error={invalid}>\n          <Listbox id={id} scroll tag=\"div\">\n            {options.map((option, index) => (\n              <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n                <Checkbox\n                  checked={selectedIndexes[index] || false}\n                  className=\"v-flex-shrink-0\"\n                  id={`${id}-option-${index}`}\n                  name={`${id}-options`}\n                  onChange={e => onSelectionChange(e, index)}\n                />\n                <Label tag=\"span\">{option}</Label>\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </ListboxContainer>\n        {invalid && (\n          <InputMessage id={`${id}-message`}>\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </fieldset>\n      <Utility vFlex vFlexRow vGap={8}>\n        <Utility element={<Button type=\"submit\" />} vMarginTop={8}>\n          Submit\n        </Utility>\n        <Utility element={<Button colorScheme=\"secondary\" type=\"reset\" />} vMarginTop={8}>\n          Reset\n        </Utility>\n      </Utility>\n    </form>\n  );\n};\n"
          },
          "name": "Multi-select listbox with error"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/disabled-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/disabled-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const DisabledMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer disabled>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox\n                className=\"v-flex-shrink-0\"\n                disabled\n                id={`${id}-option-${index}`}\n                name={`${id}-option-${index}`}\n              />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Disabled multi-select listbox"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select listboxes",
          "url": {
            "iframe": "components/listbox/item-disabled-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/item-disabled-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Checkbox, Label, Listbox, ListboxContainer, ListboxItem } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'item-disabled-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const ItemDisabledMultiListbox = () => {\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox id={id} scroll tag=\"div\">\n          {options.map((option, index) => (\n            <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n              <Checkbox\n                className=\"v-flex-shrink-0\"\n                disabled={index === 1}\n                id={`${id}-option-${index}`}\n                name={`${id}-option-${index}`}\n              />\n              <Label tag=\"span\">{option}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Multi-select listbox with disabled item"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Custom listboxes",
          "url": {
            "iframe": "components/listbox/option-single-listbox",
            "github": "apps/workshop/src/examples/components/listbox/option-single-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, useListbox } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'option-single-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const OptionSingleListbox = () => {\n  const {\n    isIndexSelected,\n    getTabIndex,\n    onKeyNavigation,\n    ref: listItemsRef,\n    toggleIndexSelected,\n  } = useListbox({ defaultSelected: 0 }); // Default to selected on first list item\n\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox aria-labelledby={`${id}-legend`} id={id} onKeyDown={onKeyNavigation} role=\"listbox\" scroll>\n          {options.map((option, index) => {\n            const disabled = index === 1;\n            return (\n              <ListboxItem\n                aria-disabled={disabled || undefined}\n                aria-selected={isIndexSelected(index)}\n                key={`${id}-option-${index}`}\n                onClick={() => toggleIndexSelected(index)}\n                ref={el => {\n                  listItemsRef.current[index] = el;\n                }}\n                role=\"option\"\n                tabIndex={getTabIndex(index, disabled)}\n              >\n                <span className=\"v-radio v-flex-shrink-0 \" />\n                {option}\n              </ListboxItem>\n            );\n          })}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Single-select listbox with custom hook"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Custom listboxes",
          "url": {
            "iframe": "components/listbox/option-multi-listbox",
            "github": "apps/workshop/src/examples/components/listbox/option-multi-listbox.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, useListbox } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'option-multi-select-listbox';\n\nconst options = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E', 'Item F', 'Item G'];\n\nexport const OptionMultiListbox = () => {\n  const {\n    isIndexSelected,\n    getTabIndex,\n    onKeyNavigation,\n    ref: listItemsRef,\n    toggleIndexSelected,\n  } = useListbox({ defaultSelected: [0, 3] }); // Default to active on first list item\n\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox aria-labelledby={`${id}-legend`} id={id} onKeyDown={onKeyNavigation} role=\"listbox\" scroll>\n          {options.map((option, index) => {\n            const disabled = index === 1;\n            return (\n              <ListboxItem\n                aria-disabled={disabled || undefined}\n                aria-selected={isIndexSelected(index)}\n                key={`${id}-option-${index}`}\n                onClick={() => toggleIndexSelected(index)}\n                ref={el => {\n                  listItemsRef.current[index] = el;\n                }}\n                role=\"option\"\n                tabIndex={getTabIndex(index, disabled)}\n              >\n                <span className=\"v-checkbox v-flex-shrink-0\" />\n                {option}\n              </ListboxItem>\n            );\n          })}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Multi-select listbox with custom hook"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Custom listboxes",
          "url": {
            "iframe": "components/listbox/reusable",
            "github": "apps/workshop/src/examples/components/listbox/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Radio,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useEffect, useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Types\nexport interface ListboxOption {\n  disabled?: boolean;\n  label: string;\n  value: number | string;\n}\n\nexport type ListboxValue = number | string | (number | string)[];\n\n// Nova Listbox Component Props\nexport interface NovaListboxProps {\n  autoSelect?: boolean;\n  containHeight?: boolean;\n  disabled?: boolean;\n  id?: string;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  multiselect?: boolean;\n  onChange?: (value: ListboxValue) => void;\n  options?: ListboxOption[];\n  value?: ListboxValue;\n}\n\n// Main Nova Listbox Component\nexport const NovaListbox = ({\n  autoSelect = false,\n  containHeight = true,\n  disabled = false,\n  id: idProp,\n  invalid = false,\n  label = '',\n  message,\n  multiselect = false,\n  onChange,\n  options = [],\n  value: valueProp,\n  ...remainingProps\n}: NovaListboxProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  // Initialize state based on multiselect mode\n  const [value, setValue] = useState<ListboxValue>(() => {\n    if (valueProp !== undefined) {\n      return valueProp;\n    }\n    return multiselect ? [] : '';\n  });\n\n  // Sync internal value with prop value\n  useEffect(() => {\n    if (valueProp !== undefined) {\n      setValue(valueProp);\n    }\n  }, [valueProp]);\n\n  // Adjust value type if multiselect mode changes\n  useEffect(() => {\n    const isArray = Array.isArray(value);\n    if (multiselect && !isArray) {\n      const newValue = value ? [value] : [];\n      setValue(newValue);\n      onChange?.(newValue);\n    } else if (!multiselect && isArray) {\n      const newValue = value[0] ?? '';\n      setValue(newValue);\n      onChange?.(newValue);\n    }\n  }, [multiselect, value, onChange]);\n\n  // Auto-select first enabled option if autoSelect is true\n  useEffect(() => {\n    if (autoSelect && options.length > 0 && !value) {\n      const firstEnabledOption = options.find(opt => !opt.disabled);\n      if (firstEnabledOption) {\n        const newValue = multiselect ? [firstEnabledOption.value] : firstEnabledOption.value;\n        setValue(newValue);\n        onChange?.(newValue);\n      }\n    }\n  }, [autoSelect, options, multiselect, value, onChange]);\n\n  // Calculate aria-describedby\n  const listboxDescribedBy = useMemo(() => {\n    const labelId = `${id}-label`;\n    const messageId = message ? `${id}-message` : null;\n    return [labelId, messageId].filter(Boolean).join(' ');\n  }, [id, message]);\n\n  const handleSingleSelect = (optionValue: number | string) => {\n    if (disabled) return;\n    setValue(optionValue);\n    onChange?.(optionValue);\n  };\n\n  const handleMultiSelect = (optionValue: number | string, checked: boolean) => {\n    if (disabled) return;\n    const currentValues = Array.isArray(value) ? value : [];\n    const newValue = checked ? [...currentValues, optionValue] : currentValues.filter(v => v !== optionValue);\n    setValue(newValue);\n    onChange?.(newValue);\n  };\n\n  const isSelected = (optionValue: number | string): boolean => {\n    if (multiselect) {\n      return Array.isArray(value) && value.includes(optionValue);\n    }\n    return value === optionValue;\n  };\n\n  return (\n    <fieldset aria-invalid={invalid}>\n      <Label id={`${id}-label`} tag=\"legend\" htmlFor={`${id}-listbox-container`}>\n        {label}\n      </Label>\n      <ListboxContainer id={`${id}-listbox-container`} error={invalid}>\n        <Listbox\n          aria-invalid={invalid}\n          aria-labelledby={listboxDescribedBy}\n          id={`${id}-listbox`}\n          scroll={containHeight}\n          tag=\"div\"\n          {...remainingProps}\n        >\n          {options.map((option, index) => (\n            <ListboxItem<'label'>\n              key={`${id}-option-${option.value}`}\n              htmlFor={`${id}-option-${index}`}\n              tag=\"label\"\n              aria-disabled={option.disabled}\n            >\n              {multiselect ? (\n                <Checkbox\n                  checked={isSelected(option.value)}\n                  className=\"v-flex-shrink-0\"\n                  disabled={disabled || option.disabled}\n                  id={`${id}-option-${index}`}\n                  name={`${id}-option-${index}`}\n                  onChange={e => handleMultiSelect(option.value, e.target.checked)}\n                />\n              ) : (\n                <Radio\n                  checked={isSelected(option.value)}\n                  className=\"v-flex-shrink-0\"\n                  disabled={disabled || option.disabled}\n                  id={`${id}-option-${index}`}\n                  name={`${id}-options`}\n                  onChange={() => handleSingleSelect(option.value)}\n                />\n              )}\n              <Label tag=\"span\">{option.label}</Label>\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n      <UtilityFragment vMarginTop={4}>\n        <InputMessage\n          id={`${id}-message`}\n          role={invalid ? 'alert' : undefined}\n          aria-live={invalid ? 'polite' : undefined}\n          aria-atomic={invalid ? true : undefined}\n        >\n          {invalid && message && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </UtilityFragment>\n    </fieldset>\n  );\n};\n\n// export default NovaListbox;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  autoSelect: boolean;\n  containHeight: boolean;\n  disabled: boolean;\n  invalid: boolean;\n  label: string;\n  message: string;\n  multiselect: boolean;\n  options: string;\n}\n\nconst demoOptions: ListboxOption[] = Array.from({ length: 5 }, (_, i) => ({\n  label: `Item ${String.fromCharCode('A'.charCodeAt(0) + i)}`,\n  value: `option-${i + 1}`,\n}));\n\n// Demo Component\nexport const NovaListboxDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    autoSelect: false,\n    containHeight: true,\n    disabled: false,\n    invalid: false,\n    label: 'Label (required)',\n    message: 'This is optional text that describes the label in more detail.',\n    multiselect: false,\n    options: JSON.stringify(demoOptions, null, 4),\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'options'> & { options: ListboxOption[] }\n  >({\n    ...defaultCustomizations,\n    options: demoOptions,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n  const [selectedValue, setSelectedValue] = useState<ListboxValue>('');\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.options || '[]') as ListboxOption[];\n      setCustomizations({\n        ...formValues,\n        options: parsedOptions,\n      });\n      // Reset selected value when applying changes\n      setSelectedValue(formValues.multiselect ? [] : '');\n    } catch (error) {\n      console.error('Invalid JSON:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      options: demoOptions,\n    });\n    setSelectedValue('');\n  };\n\n  return (\n    <div>\n      <NovaListbox\n        autoSelect={customizations.autoSelect}\n        containHeight={customizations.containHeight}\n        disabled={customizations.disabled}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.message || ''}\n        multiselect={customizations.multiselect}\n        onChange={setSelectedValue}\n        options={customizations.options}\n        value={selectedValue}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              <NovaInput<'textarea'>\n                fixed={false}\n                label=\"Options\"\n                onChange={e => handleInputChange('options', e.target.value)}\n                style={{ blockSize: '100px' }}\n                textarea\n                value={formValues.options}\n              />\n\n              <NovaCheckbox\n                label=\"Auto select\"\n                checked={formValues.autoSelect}\n                onChange={e => handleInputChange('autoSelect', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Contain height\"\n                checked={formValues.containHeight}\n                onChange={e => handleInputChange('containHeight', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Multiselect\"\n                checked={formValues.multiselect}\n                onChange={e => handleInputChange('multiselect', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaListboxDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable listbox"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Listbox",
          "selector": "<Listbox />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container that displays a list of items available for selection."
        },
        {
          "order": 2,
          "name": "Listboxcontainer",
          "selector": "<ListboxContainer />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for listbox component."
        },
        {
          "order": 3,
          "name": "Listboxitem",
          "selector": "<ListboxItem />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for elements used inside listbox."
        },
        {
          "order": 4,
          "name": "useListbox",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to manage the selected state and keyboard navigation of listbox component."
        }
      ],
      "properties": [
        {
          "name": "multiselect",
          "section": "Listbox",
          "data": {
            "name": "multiselect",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Multiselect"
          }
        },
        {
          "name": "scroll",
          "section": "Listbox",
          "data": {
            "name": "scroll",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Scroll"
          }
        },
        {
          "name": "tag",
          "section": "Listbox",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "ul",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "disabled",
          "section": "Listboxcontainer",
          "data": {
            "name": "disabled",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Is Disabled"
          }
        },
        {
          "name": "error",
          "section": "Listboxcontainer",
          "data": {
            "name": "error",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Error"
          }
        },
        {
          "name": "tag",
          "section": "Listboxcontainer",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Listboxitem",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "li",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "multiselect",
      "version": "0.0.1",
      "description": "Control that allows users to select multiple options from a dropdown menu.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default multiselects",
          "description": "",
          "order": 1
        },
        {
          "name": "Multiselect Behaviors",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom multiselect",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/default-multiselect",
            "github": "apps/workshop/src/examples/components/multiselect/default-multiselect.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'default-multiselect';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const DefaultMultiselect = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Default multiselect"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-inline-message",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-inline-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-inline-message';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithInlineMessage = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n          <UtilityFragment vHide={isOpen}>\n            <InputMessage id={`${id}-message`}>\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with inline message"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-error",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-error.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useRef, useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-error';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithError = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem, reset } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n      if (type === useMultipleSelection.stateChangeTypes.FunctionReset) {\n        setSelectedItems([]);\n        setInputValue('');\n        setHasError(false);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  const [hasError, setHasError] = useState(false);\n  const dropdownRef = useRef<HTMLInputElement | null>(null);\n\n  const handleSubmit = () => {\n    // Customize this for your own validation needs\n    if (!selectedItems.length) {\n      setHasError(true);\n    }\n\n    // Focus on the field with the error\n    if (dropdownRef.current) {\n      dropdownRef.current.focus();\n    }\n  };\n  const handleReset = () => {\n    reset();\n  };\n\n  return (\n    <>\n      <Combobox>\n        <UtilityFragment vFlex vFlexCol vGap={4}>\n          <DropdownContainer>\n            <Label {...getLabelProps()}>Label (required)</Label>\n            <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n              <InputContainer>\n                <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                  {selectedItems.map((item, index) => (\n                    <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                      <Chip chipSize=\"compact\">\n                        <Label>{item.value}</Label>\n                        <Button\n                          aria-label={`Remove ${item.value}`}\n                          colorScheme=\"tertiary\"\n                          iconButton\n                          onClick={() => removeSelectedItem(item)}\n                          subtle\n                        >\n                          <VisaClearAltTiny />\n                        </Button>\n                      </Chip>\n                    </UtilityFragment>\n                  ))}\n                  <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                    <Input\n                      name={id}\n                      aria-invalid={hasError}\n                      {...getInputProps(\n                        getDropdownProps({\n                          ref: dropdownRef,\n                          onKeyDown: e => {\n                            if (e.key === 'Enter') {\n                              if (highlightedIndex !== -1 && isOpen) {\n                                const selectedItem = items[highlightedIndex];\n                                if (selectedItems.includes(selectedItem)) {\n                                  removeSelectedItem(selectedItem);\n                                } else {\n                                  setSelectedItems([...selectedItems, selectedItem]);\n                                  setInputValue('');\n                                  setHasError(false);\n                                }\n                              }\n                            }\n                          },\n                        })\n                      )}\n                    />\n                  </UtilityFragment>\n                </Utility>\n                <Button\n                  aria-haspopup=\"listbox\"\n                  aria-label={`${id}-toggle-button`}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  {...getToggleButtonProps()}\n                >\n                  {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                </Button>\n              </InputContainer>\n            </UtilityFragment>\n            {hasError && (\n              <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`} role=\"alert\">\n                <VisaErrorTiny />\n                This is required text that describes the error in more detail.\n              </InputMessage>\n            )}\n          </DropdownContainer>\n        </UtilityFragment>\n        <ListboxContainer>\n          <UtilityFragment vFlex>\n            <Listbox {...getMenuProps()}>\n              {items.map((item, index) => (\n                <ListboxItem<'li'>\n                  key={`${id}-example-${index}`}\n                  className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                  {...getItemProps({\n                    item,\n                    index,\n                    'aria-selected': selectedItems.includes(item),\n                    onClick: () => {\n                      if (selectedItems.includes(item)) {\n                        removeSelectedItem(item);\n                      } else {\n                        setSelectedItems([...selectedItems, item]);\n                        setInputValue('');\n                        setHasError(false);\n                      }\n                    },\n                  })}\n                >\n                  <Checkbox tag=\"span\" />\n                  {item.value}\n                </ListboxItem>\n              ))}\n            </Listbox>\n          </UtilityFragment>\n        </ListboxContainer>\n      </Combobox>\n      <Utility vFlex vGap={12} vMarginTop={16}>\n        <Button id={`${id}-submit-button`} onClick={handleSubmit}>\n          Submit\n        </Button>\n        <Button id={`${id}-reset-button`} colorScheme=\"secondary\" onClick={handleReset}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Multiselect with error"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-disabled-option",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-disabled-option.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string; disabled?: boolean };\n\nconst id = 'multiselect-with-disabled-option';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B', disabled: true },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithDisabledOption = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    isItemDisabled: item => !!item.disabled,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  'aria-disabled': item.disabled,\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with disabled option"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/disabled-multiselect",
            "github": "apps/workshop/src/examples/components/multiselect/disabled-multiselect.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'disabled-multiselect';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const DisabledMultiselect = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const [isDisabled, setIsDisabled] = useState(true);\n\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <>\n      <Combobox>\n        <UtilityFragment vFlex vFlexCol vGap={4}>\n          <DropdownContainer>\n            <Label {...getLabelProps()}>Label (required)</Label>\n            <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n              <InputContainer>\n                <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                  {selectedItems.map((item, index) => (\n                    <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                      <Chip chipSize=\"compact\">\n                        <Label>{item.value}</Label>\n                        <Button\n                          aria-label={`Remove ${item.value}`}\n                          colorScheme=\"tertiary\"\n                          iconButton\n                          onClick={() => removeSelectedItem(item)}\n                          subtle\n                          disabled={isDisabled}\n                        >\n                          <VisaClearAltTiny />\n                        </Button>\n                      </Chip>\n                    </UtilityFragment>\n                  ))}\n                  <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                    <Input\n                      name={id}\n                      disabled={isDisabled}\n                      {...getInputProps(\n                        getDropdownProps({\n                          onKeyDown: e => {\n                            if (e.key === 'Enter') {\n                              if (highlightedIndex !== -1 && isOpen) {\n                                const selectedItem = items[highlightedIndex];\n                                if (selectedItems.includes(selectedItem)) {\n                                  removeSelectedItem(selectedItem);\n                                } else {\n                                  setSelectedItems([...selectedItems, selectedItem]);\n                                  setInputValue('');\n                                }\n                              }\n                            }\n                          },\n                        })\n                      )}\n                    />\n                  </UtilityFragment>\n                </Utility>\n                <Button\n                  aria-haspopup=\"listbox\"\n                  aria-label={`${id}-toggle-button`}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  disabled={isDisabled}\n                  {...getToggleButtonProps()}\n                >\n                  {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                </Button>\n              </InputContainer>\n            </UtilityFragment>\n          </DropdownContainer>\n        </UtilityFragment>\n        <ListboxContainer>\n          <UtilityFragment vFlex>\n            <Listbox {...getMenuProps()}>\n              {items.map((item, index) => (\n                <ListboxItem<'li'>\n                  key={`${id}-example-${index}`}\n                  className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                  {...getItemProps({\n                    item,\n                    index,\n                    'aria-selected': selectedItems.includes(item),\n                    onClick: () => {\n                      if (selectedItems.includes(item)) {\n                        removeSelectedItem(item);\n                      } else {\n                        setSelectedItems([...selectedItems, item]);\n                        setInputValue('');\n                      }\n                    },\n                  })}\n                >\n                  <Checkbox tag=\"span\" />\n                  {item.value}\n                </ListboxItem>\n              ))}\n            </Listbox>\n          </UtilityFragment>\n        </ListboxContainer>\n      </Combobox>\n      <Utility className=\"v-input-container\" vMarginTop={10}>\n        <Checkbox\n          id={`${id}-checkbox-mark-as-disabled`}\n          onChange={() => setIsDisabled(currentValue => !currentValue)}\n          checked={isDisabled}\n        />\n        <Label htmlFor={`${id}-checkbox-mark-as-disabled`}>Mark input as disabled</Label>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Disabled multiselect"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/read-only-multiselect",
            "github": "apps/workshop/src/examples/components/multiselect/read-only-multiselect.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'read-only-multiselect';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const ReadOnlyMultiselect = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const [isReadOnly, setIsReadOnly] = useState(true);\n\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <>\n      <Combobox>\n        <UtilityFragment vFlex vFlexCol vGap={4}>\n          <DropdownContainer>\n            <Label {...getLabelProps()}>Label (required)</Label>\n            <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n              <InputContainer>\n                <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                  {selectedItems.map((item, index) => (\n                    <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                      <Chip chipSize=\"compact\">\n                        {isReadOnly ? (\n                          item.value\n                        ) : (\n                          <>\n                            <Label>{item.value}</Label>\n                            <Button\n                              aria-label={`Remove ${item.value}`}\n                              colorScheme=\"tertiary\"\n                              iconButton\n                              onClick={() => removeSelectedItem(item)}\n                              subtle\n                            >\n                              <VisaClearAltTiny />\n                            </Button>\n                          </>\n                        )}\n                      </Chip>\n                    </UtilityFragment>\n                  ))}\n                  <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                    <Input\n                      name={id}\n                      readOnly={isReadOnly}\n                      {...getInputProps(\n                        getDropdownProps({\n                          onKeyDown: e => {\n                            if (e.key === 'Enter') {\n                              if (highlightedIndex !== -1 && isOpen) {\n                                const selectedItem = items[highlightedIndex];\n                                if (selectedItems.includes(selectedItem)) {\n                                  removeSelectedItem(selectedItem);\n                                } else {\n                                  setSelectedItems([...selectedItems, selectedItem]);\n                                  setInputValue('');\n                                }\n                              }\n                            }\n                          },\n                        })\n                      )}\n                    />\n                  </UtilityFragment>\n                </Utility>\n                <Button\n                  aria-haspopup=\"listbox\"\n                  aria-label={`${id}-toggle-button`}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  disabled={isReadOnly}\n                  {...getToggleButtonProps()}\n                >\n                  {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                </Button>\n              </InputContainer>\n            </UtilityFragment>\n          </DropdownContainer>\n        </UtilityFragment>\n        <ListboxContainer>\n          <UtilityFragment vFlex>\n            <Listbox {...getMenuProps()}>\n              {items.map((item, index) => (\n                <ListboxItem<'li'>\n                  key={`${id}-example-${index}`}\n                  className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                  {...getItemProps({\n                    item,\n                    index,\n                    'aria-selected': selectedItems.includes(item),\n                    onClick: () => {\n                      if (selectedItems.includes(item)) {\n                        removeSelectedItem(item);\n                      } else {\n                        setSelectedItems([...selectedItems, item]);\n                        setInputValue('');\n                      }\n                    },\n                  })}\n                >\n                  <Checkbox tag=\"span\" />\n                  {item.value}\n                </ListboxItem>\n              ))}\n            </Listbox>\n          </UtilityFragment>\n        </ListboxContainer>\n      </Combobox>\n      <Utility className=\"v-input-container\" vMarginTop={10}>\n        <Checkbox\n          id={`${id}-checkbox-mark-as-read-only`}\n          onChange={() => setIsReadOnly(currentValue => !currentValue)}\n          checked={isReadOnly}\n        />\n        <Label htmlFor={`${id}-checkbox-mark-as-read-only`}>Mark input as read-only</Label>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Read-only multiselect"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-without-dropdown-chevron",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-without-dropdown-chevron.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-without-dropdown-chevron';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithoutDropdownChevron = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const { getLabelProps, getMenuProps, getInputProps, getItemProps, highlightedIndex, isOpen, setHighlightedIndex } =\n    useCombobox({\n      id,\n      items,\n      itemToString,\n      inputValue,\n      stateReducer: comboboxStateReducer,\n      onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n        if (type === useCombobox.stateChangeTypes.InputChange) {\n          setInputValue(newInputValue!);\n        }\n        if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n          // make sure the highlighted index is on the item that was just clicked\n          setHighlightedIndex(items.indexOf(selectedItem));\n        }\n      },\n    });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect without dropdown chevron"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-multiple-selections-and-vertical-scroll",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-multiple-selections-and-vertical-scroll.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-multiple-selections-and-vertical-scroll';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n  { value: 'Option F' },\n  { value: 'Option G' },\n  { value: 'Option H' },\n  { value: 'Option I' },\n  { value: 'Option J' },\n  { value: 'Option K' },\n  { value: 'Option L' },\n  { value: 'Option M' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithMultipleSelectionsAndVerticalScroll = () => {\n  const items = multiselectItems;\n  const [inputValue, setInputValue] = useState('');\n\n  // preselect the first 11 items to demonstrate a very full input field with scrollbar\n  const [selectedItems, setSelectedItems] = useState<Item[]>(items.slice(0, 12));\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox style={{ maxInlineSize: '290px' }}>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility\n                vFlex\n                vFlexGrow\n                vFlexShrink\n                vFlexWrap\n                vGap={2}\n                style={{ maxBlockSize: '140px', overflowY: 'auto' }}\n              >\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox scroll {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with multiple selections and vertical scroll"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-select-and-unselect-all-buttons",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-select-and-unselect-all-buttons.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  Divider,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-select-and-unselect-all-buttons';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        // if an item was selected/removed, keep the menu open and maintain the same highlightedIndex\n        ...(changes.selectedItem && { isOpen: true, highlightedIndex: state.highlightedIndex }),\n      };\n    case useCombobox.stateChangeTypes.InputBlur: // Keep the menu open for focusing on the select/clear all buttons\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithSelectAndUnselectAllButtons = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <>\n          <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vPaddingHorizontal={8}>\n            <Button colorScheme=\"tertiary\" onClick={() => setSelectedItems(multiselectItems)}>\n              Select All\n            </Button>\n            <Button colorScheme=\"tertiary\" destructive onClick={() => setSelectedItems([])}>\n              Clear All\n            </Button>\n          </Utility>\n          <Divider dividerType=\"decorative\" />\n        </>\n        <UtilityFragment vFlex>\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with select and unselect all buttons"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Default multiselects",
          "url": {
            "iframe": "components/multiselect/multiselect-with-scrollbar",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-scrollbar.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-scrollbar';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n  { value: 'Option F' },\n  { value: 'Option G' },\n  { value: 'Option H' },\n  { value: 'Option I' },\n  { value: 'Option J' },\n  { value: 'Option K' },\n  { value: 'Option L' },\n  { value: 'Option M' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        // don't update the highlighted index\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithScrollbar = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = multiselectItems;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment vFlex>\n          <Listbox scroll {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with scrollbar"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Multiselect Behaviors",
          "url": {
            "iframe": "components/multiselect/multiselect-with-filterable-menu-and-manual-selection",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-filterable-menu-and-manual-selection.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useMemo, useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-filterable-menu-and-manual-selection';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithFilterableMenuAndManualSelection = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = useMemo(\n    () => multiselectItems.filter(item => item.value.toLowerCase().includes(inputValue.toLowerCase())),\n    [inputValue]\n  );\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id,\n    items,\n    itemToString,\n    inputValue,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue!);\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && !!selectedItem) {\n        // make sure the highlighted index is on the item that was just clicked\n        setHighlightedIndex(items.indexOf(selectedItem));\n      }\n    },\n  });\n\n  const resultsFound = items.length > 0;\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      <Label>{item.value}</Label>\n                      <Button\n                        aria-label={`Remove ${item.value}`}\n                        colorScheme=\"tertiary\"\n                        iconButton\n                        onClick={() => removeSelectedItem(item)}\n                        subtle\n                      >\n                        <VisaClearAltTiny />\n                      </Button>\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && resultsFound && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment\n          vAlignItems={resultsFound ? undefined : 'center'}\n          vFlex={resultsFound || undefined}\n          vJustifyContent={resultsFound ? undefined : 'center'}\n          style={resultsFound ? undefined : { minBlockSize: 180 }}\n        >\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n            {!resultsFound && (\n              <li aria-atomic=\"true\" aria-live=\"assertive\">\n                <Typography variant=\"label-large\">No results found</Typography>\n              </li>\n            )}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with filterable menu and manual selection"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Multiselect Behaviors",
          "url": {
            "iframe": "components/multiselect/multiselect-with-filterable-menu-and-automatic-selection",
            "github": "apps/workshop/src/examples/components/multiselect/multiselect-with-filterable-menu-and-automatic-selection.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useCombobox, useMultipleSelection, type UseComboboxState, type UseComboboxStateChangeOptions } from 'downshift';\nimport { useMemo, useState } from 'react';\n\ntype Item = { value: string };\n\nconst id = 'multiselect-with-filterable-menu-and-automatic-selection';\nconst multiselectItems: Item[] = [\n  { value: 'Option A' },\n  { value: 'Option B' },\n  { value: 'Option C' },\n  { value: 'Option D' },\n  { value: 'Option E' },\n];\n\nexport const itemToString = (item: Item | null) => (item ? item.value : '');\n\nexport const comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        // don't open the menu just because the input was clicked\n        // instead, wait for an keystroke or a toggle button click\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        // don't change the focused item just because the mouse moved\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        isOpen: true, // keep the menu open on item select or Enter press\n        // and if we're selecting an item, maintain the same highlightedIndex\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\nexport const MultiselectWithFilterableMenuAndAutomaticSelection = () => {\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<Item[]>([]);\n  const items = useMemo(\n    () => multiselectItems.filter(item => item.value.toLowerCase().includes(inputValue.toLowerCase())),\n    [inputValue]\n  );\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        setSelectedItems(newSelectedItems!);\n      }\n    },\n  });\n  const { getToggleButtonProps, getLabelProps, getMenuProps, getInputProps, getItemProps, highlightedIndex, isOpen } =\n    useCombobox({\n      id,\n      items,\n      itemToString,\n      inputValue,\n      defaultHighlightedIndex: 0, // after selection, highlight the first item.\n      stateReducer: comboboxStateReducer,\n      onStateChange({ inputValue: newInputValue, type }) {\n        if (type === useCombobox.stateChangeTypes.InputChange) {\n          setInputValue(newInputValue!);\n        }\n      },\n    });\n\n  const resultsFound = items.length > 0;\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Label {...getLabelProps()}>Label (required)</Label>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => {\n                  return (\n                    <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                      <Chip chipSize=\"compact\">\n                        <Label>{item.value}</Label>\n                        <Button\n                          aria-label={`Remove ${item.value}`}\n                          colorScheme=\"tertiary\"\n                          iconButton\n                          onClick={() => removeSelectedItem(item)}\n                          subtle\n                        >\n                          <VisaClearAltTiny />\n                        </Button>\n                      </Chip>\n                    </UtilityFragment>\n                  );\n                })}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    name={id}\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && resultsFound && isOpen) {\n                              const selectedItem = items[highlightedIndex];\n                              if (selectedItems.includes(selectedItem)) {\n                                removeSelectedItem(selectedItem);\n                              } else {\n                                setSelectedItems([...selectedItems, selectedItem]);\n                                setInputValue('');\n                              }\n                            }\n                          }\n                        },\n                      })\n                    )}\n                  />\n                </UtilityFragment>\n              </Utility>\n              <Button\n                aria-haspopup=\"listbox\"\n                aria-label={`${id}-toggle-button`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                {...getToggleButtonProps()}\n              >\n                {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n              </Button>\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n      <ListboxContainer>\n        <UtilityFragment\n          vAlignItems={resultsFound ? undefined : 'center'}\n          vFlex={resultsFound || undefined}\n          vJustifyContent={resultsFound ? undefined : 'center'}\n          style={resultsFound ? undefined : { minBlockSize: 180 }}\n        >\n          <Listbox {...getMenuProps()}>\n            {items.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-example-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => {\n                    if (selectedItems.includes(item)) {\n                      removeSelectedItem(item);\n                    } else {\n                      setSelectedItems([...selectedItems, item]);\n                      setInputValue('');\n                    }\n                  },\n                })}\n              >\n                <Checkbox tag=\"span\" />\n                {item.value}\n              </ListboxItem>\n            ))}\n            {!resultsFound && (\n              <li aria-atomic=\"true\" aria-live=\"assertive\">\n                <Typography variant=\"label-large\">No results found</Typography>\n              </li>\n            )}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n"
          },
          "name": "Multiselect with filterable menu and automatic selection"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Custom multiselect",
          "url": {
            "iframe": "components/multiselect/reusable",
            "github": "apps/workshop/src/examples/components/multiselect/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronUpTiny, VisaClearAltTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Checkbox,\n  Chip,\n  Combobox,\n  Divider,\n  DropdownContainer,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport {\n  type UseComboboxState,\n  type UseComboboxStateChangeOptions,\n  useCombobox,\n  useMultipleSelection,\n} from 'downshift';\nimport { useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Types\nexport interface MultiselectOption<T = string> {\n  disabled?: boolean;\n  label: string;\n  value: T;\n}\n\n// Nova Multiselect Component Props\nexport interface NovaMultiselectProps<T = string> {\n  autoFilter?: boolean;\n  autoSelect?: boolean;\n  description?: string;\n  disabled?: boolean;\n  hideDropdownButton?: boolean;\n  hideSelectionButtons?: boolean;\n  id?: string;\n  inline?: boolean;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  onChange?: (selectedValues: T[]) => void;\n  options?: MultiselectOption<T>[];\n  readonly?: boolean;\n  required?: boolean;\n  value?: T[];\n}\n\n// Combobox state reducer\nconst comboboxStateReducer = <ItemType,>(\n  state: UseComboboxState<ItemType>,\n  { type, changes }: UseComboboxStateChangeOptions<ItemType>\n) => {\n  switch (type) {\n    case useCombobox.stateChangeTypes.InputClick:\n      return {\n        ...state,\n      };\n    case useCombobox.stateChangeTypes.InputChange:\n      return {\n        ...changes,\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.ItemMouseMove:\n    case useCombobox.stateChangeTypes.MenuMouseLeave:\n      return {\n        ...changes,\n        highlightedIndex: state.highlightedIndex,\n      };\n    case useCombobox.stateChangeTypes.InputKeyDownEnter:\n    case useCombobox.stateChangeTypes.ItemClick:\n      return {\n        ...changes,\n        ...(changes.selectedItem && { isOpen: true, highlightedIndex: state.highlightedIndex }),\n      };\n    case useCombobox.stateChangeTypes.InputBlur:\n      return {\n        ...changes,\n        isOpen: true,\n        ...(changes.selectedItem && { highlightedIndex: state.highlightedIndex }),\n      };\n    default:\n      return changes;\n  }\n};\n\n// Item to string converter\nconst itemToString = <T,>(item: MultiselectOption<T> | null) => (item ? item.label : '');\n\n// Main Nova Multiselect Component\nexport const NovaMultiselect = <T = string,>({\n  autoFilter = true,\n  autoSelect = false,\n  description,\n  disabled = false,\n  hideDropdownButton = false,\n  hideSelectionButtons = false,\n  id: idProp,\n  inline = false,\n  invalid = false,\n  label = '',\n  message,\n  onChange,\n  options = [],\n  readonly = false,\n  required = false,\n  value = [],\n  ...remainingProps\n}: NovaMultiselectProps<T>) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const [inputValue, setInputValue] = useState('');\n  const [selectedItems, setSelectedItems] = useState<MultiselectOption<T>[]>(() =>\n    options.filter(opt => value.includes(opt.value))\n  );\n\n  // Filter options based on input value\n  const filteredItems = useMemo(() => {\n    if (!autoFilter || !inputValue) return options;\n    return options.filter(item => item.label.toLowerCase().includes(inputValue.toLowerCase()));\n  }, [autoFilter, inputValue, options]);\n\n  // Calculate aria-describedby\n  const inputDescribedBy =\n    message || description\n      ? [message ? `${id}-message` : '', description ? `${id}-description` : ''].filter(Boolean).join(' ')\n      : undefined;\n\n  const { getDropdownProps, removeSelectedItem } = useMultipleSelection({\n    selectedItems,\n    onStateChange({ selectedItems: newSelectedItems, type }) {\n      if (\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete ||\n        type === useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace ||\n        type === useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem\n      ) {\n        const updatedItems = newSelectedItems || [];\n        setSelectedItems(updatedItems);\n        onChange?.(updatedItems.map(item => item.value));\n      }\n    },\n  });\n\n  const {\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    getInputProps,\n    getItemProps,\n    highlightedIndex,\n    isOpen,\n    setHighlightedIndex,\n  } = useCombobox({\n    id: `${id}-combobox`,\n    items: filteredItems,\n    itemToString,\n    inputValue,\n    defaultHighlightedIndex: 0,\n    stateReducer: comboboxStateReducer,\n    onStateChange({ inputValue: newInputValue, type, selectedItem }) {\n      if (type === useCombobox.stateChangeTypes.InputChange) {\n        setInputValue(newInputValue || '');\n\n        // Auto-select if enabled and there's only one filtered result\n        if (autoSelect && newInputValue) {\n          const filtered = options.filter(item => item.label.toLowerCase().includes(newInputValue.toLowerCase()));\n          if (filtered.length === 1 && !selectedItems.includes(filtered[0])) {\n            const newSelectedItems = [...selectedItems, filtered[0]];\n            setSelectedItems(newSelectedItems);\n            onChange?.(newSelectedItems.map(item => item.value));\n            setInputValue('');\n          }\n        }\n      }\n      if (type === useCombobox.stateChangeTypes.ItemClick && selectedItem) {\n        setHighlightedIndex(filteredItems.indexOf(selectedItem));\n      }\n    },\n  });\n\n  const handleItemSelect = (item: MultiselectOption<T>) => {\n    if (item.disabled) return;\n\n    if (selectedItems.includes(item)) {\n      removeSelectedItem(item);\n    } else {\n      const newSelectedItems = [...selectedItems, item];\n      setSelectedItems(newSelectedItems);\n      onChange?.(newSelectedItems.map(i => i.value));\n      setInputValue('');\n    }\n  };\n\n  const handleSelectAll = () => {\n    const enabledOptions = options.filter(opt => !opt.disabled);\n    setSelectedItems(enabledOptions);\n    onChange?.(enabledOptions.map(item => item.value));\n  };\n\n  const handleClearAll = () => {\n    setSelectedItems([]);\n    onChange?.([]);\n  };\n\n  const resultsFound = filteredItems.length > 0;\n\n  return (\n    <Combobox>\n      <UtilityFragment vFlex vFlexCol vGap={4}>\n        <DropdownContainer>\n          <Utility vFlex={inline} vFlexCol={!inline} vGap={inline ? 8 : 4}>\n            <Label {...getLabelProps()} htmlFor={`${id}-input`}>\n              {label}\n              {required ? ' (required)' : ''}\n            </Label>\n            {description && (\n              <Typography variant=\"body-3\" id={`${id}-description`} tag=\"span\">\n                {description}\n              </Typography>\n            )}\n          </Utility>\n          <UtilityFragment vPaddingVertical={3} vPaddingLeft={3} vPaddingRight={6}>\n            <InputContainer>\n              <Utility vFlex vFlexGrow vFlexShrink vFlexWrap vGap={2}>\n                {selectedItems.map((item, index) => (\n                  <UtilityFragment vFlexShrink0 key={`selected-item-${index}`}>\n                    <Chip chipSize=\"compact\">\n                      {readonly ? (\n                        item.label\n                      ) : (\n                        <>\n                          <Label>{item.label}</Label>\n                          <Button\n                            aria-label={`Remove ${item.label}`}\n                            colorScheme=\"tertiary\"\n                            iconButton\n                            onClick={() => removeSelectedItem(item)}\n                            subtle\n                            disabled={disabled}\n                          >\n                            <VisaClearAltTiny />\n                          </Button>\n                        </>\n                      )}\n                    </Chip>\n                  </UtilityFragment>\n                ))}\n                <UtilityFragment vFlexShrink style={{ flexBasis: '50px' }}>\n                  <Input\n                    {...getInputProps(\n                      getDropdownProps({\n                        onKeyDown: e => {\n                          if (e.key === 'Enter') {\n                            if (highlightedIndex !== -1 && resultsFound && isOpen) {\n                              const selectedItem = filteredItems[highlightedIndex];\n                              handleItemSelect(selectedItem);\n                            }\n                          }\n                        },\n                      })\n                    )}\n                    aria-describedby={inputDescribedBy}\n                    aria-invalid={invalid}\n                    aria-required={required ? true : undefined}\n                    disabled={disabled}\n                    id={`${id}-input`}\n                    name={`${id}-multiselect`}\n                    readOnly={readonly}\n                    {...remainingProps}\n                  />\n                </UtilityFragment>\n              </Utility>\n              {!hideDropdownButton && (\n                <Button\n                  aria-haspopup=\"listbox\"\n                  aria-label={`${id}-toggle-button`}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  disabled={disabled || readonly}\n                  {...getToggleButtonProps()}\n                >\n                  {isOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                </Button>\n              )}\n            </InputContainer>\n          </UtilityFragment>\n        </DropdownContainer>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginTop={4}>\n        <InputMessage aria-atomic={invalid ? true : undefined} aria-live={invalid ? 'assertive' : undefined}>\n          {invalid && message && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </UtilityFragment>\n\n      <ListboxContainer>\n        {!hideSelectionButtons && (\n          <>\n            <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vPaddingHorizontal={8}>\n              <Button colorScheme=\"tertiary\" onClick={handleSelectAll} disabled={disabled || readonly}>\n                Select All\n              </Button>\n              <Button colorScheme=\"tertiary\" destructive onClick={handleClearAll} disabled={disabled || readonly}>\n                Clear All\n              </Button>\n            </Utility>\n            <Divider dividerType=\"decorative\" />\n          </>\n        )}\n        <UtilityFragment\n          vAlignItems={resultsFound ? undefined : 'center'}\n          vFlex={resultsFound || undefined}\n          vJustifyContent={resultsFound ? undefined : 'center'}\n          style={resultsFound ? undefined : { minBlockSize: 180 }}\n        >\n          <Listbox {...getMenuProps()}>\n            {filteredItems.map((item, index) => (\n              <ListboxItem<'li'>\n                key={`${id}-item-${index}`}\n                className={highlightedIndex === index ? 'v-listbox-item-highlighted' : ''}\n                {...getItemProps({\n                  item,\n                  index,\n                  'aria-disabled': item.disabled || undefined,\n                  'aria-selected': selectedItems.includes(item),\n                  onClick: () => handleItemSelect(item),\n                })}\n              >\n                <Checkbox tag=\"span\" checked={selectedItems.includes(item)} disabled={item.disabled} />\n                {item.label}\n              </ListboxItem>\n            ))}\n            {!resultsFound && (\n              <li aria-atomic=\"true\" aria-live=\"assertive\">\n                <Typography variant=\"label-large\">No results found</Typography>\n              </li>\n            )}\n          </Listbox>\n        </UtilityFragment>\n      </ListboxContainer>\n    </Combobox>\n  );\n};\n// export default NovaMultiselect;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  autoFilter: boolean;\n  autoSelect: boolean;\n  description: string;\n  disabled: boolean;\n  hideDropdownButton: boolean;\n  hideSelectionButtons: boolean;\n  inline: boolean;\n  invalid: boolean;\n  label: string;\n  message: string;\n  options: string;\n  readonly: boolean;\n  required: boolean;\n}\n\nconst demoOptions: MultiselectOption[] = [\n  { label: 'Option A', value: 'a' },\n  { label: 'Option B', value: 'b' },\n  { label: 'Option C', value: 'c', disabled: true },\n  { label: 'Option D', value: 'd' },\n  { label: 'Option E', value: 'e' },\n];\n\n// Demo Component\nexport const NovaMultiselectDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    autoFilter: true,\n    autoSelect: false,\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    hideDropdownButton: false,\n    hideSelectionButtons: false,\n    inline: false,\n    invalid: false,\n    label: 'Label',\n    message: 'This is required text that describes the error in more detail.',\n    options: JSON.stringify(demoOptions, null, 2),\n    readonly: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'options'> & { options: MultiselectOption[] }\n  >({\n    ...defaultCustomizations,\n    options: demoOptions,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n  const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.options || '[]') as MultiselectOption[];\n      setCustomizations({\n        ...formValues,\n        options: parsedOptions,\n      });\n    } catch (error) {\n      console.error('Invalid JSON:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      options: demoOptions,\n    });\n    setSelectedValues([]);\n  };\n\n  return (\n    <div>\n      <NovaMultiselect\n        autoFilter={customizations.autoFilter}\n        autoSelect={customizations.autoSelect}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        hideDropdownButton={customizations.hideDropdownButton}\n        hideSelectionButtons={customizations.hideSelectionButtons}\n        inline={customizations.inline}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.message : undefined}\n        onChange={setSelectedValues}\n        options={customizations.options}\n        readonly={customizations.readonly}\n        required={customizations.required}\n        value={selectedValues}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <Typography variant=\"body-2\" tag=\"p\">\n          Selected values: {selectedValues.length > 0 ? selectedValues.join(', ') : 'None'}\n        </Typography>\n      </div>\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Error message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              <NovaInput<'textarea'>\n                fixed={false}\n                label=\"Options (JSON)\"\n                onChange={e => handleInputChange('options', e.target.value)}\n                style={{ blockSize: '150px' }}\n                textarea\n                value={formValues.options}\n              />\n\n              <NovaCheckbox\n                label=\"Auto filter\"\n                checked={formValues.autoFilter}\n                onChange={e => handleInputChange('autoFilter', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Auto select\"\n                checked={formValues.autoSelect}\n                onChange={e => handleInputChange('autoSelect', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Hide dropdown button\"\n                checked={formValues.hideDropdownButton}\n                onChange={e => handleInputChange('hideDropdownButton', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Hide selection buttons\"\n                checked={formValues.hideSelectionButtons}\n                onChange={e => handleInputChange('hideSelectionButtons', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Inline\"\n                checked={formValues.inline}\n                onChange={e => handleInputChange('inline', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Readonly\"\n                checked={formValues.readonly}\n                onChange={e => handleInputChange('readonly', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaMultiselectDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable multiselect"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "button",
          "type": "related",
          "selector": "<Button />",
          "description": ""
        },
        {
          "order": 2,
          "name": "checkbox",
          "type": "related",
          "selector": "<Checkbox />",
          "description": ""
        },
        {
          "order": 3,
          "name": "chip",
          "type": "related",
          "selector": "<Chip />",
          "description": ""
        },
        {
          "order": 4,
          "name": "combobox",
          "type": "related",
          "selector": "<Combobox />",
          "description": ""
        },
        {
          "order": 5,
          "name": "divider",
          "type": "related",
          "selector": "<Divider />",
          "description": ""
        },
        {
          "order": 6,
          "name": "input",
          "type": "related",
          "selector": "<Input />",
          "description": ""
        },
        {
          "order": 7,
          "name": "listbox",
          "type": "related",
          "selector": "<Listbox />",
          "description": ""
        },
        {
          "order": 8,
          "name": "typography",
          "type": "related",
          "selector": "<Typography />",
          "description": ""
        }
      ],
      "properties": []
    },
    {
      "name": "navigation-drawer",
      "version": "0.0.1",
      "description": "Collapsible panel or menu next to page content that links to important pages or features.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default navigation drawers",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/default-navigation-drawer",
            "github": "apps/workshop/src/examples/components/navigation-drawer/default-navigation-drawer.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-navigation-drawer';\nconst navElAriaLabel = 'Default drawer';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const DefaultNavigationDrawer = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button colorScheme=\"tertiary\" element={<a href={tabContent.href}>{tabContent.tabLabel}</a>} />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Default navigation drawer"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/navigation-drawer-with-active-element",
            "github": "apps/workshop/src/examples/components/navigation-drawer/navigation-drawer-with-active-element.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'navigation-drawer-with-active-element';\nconst navElAriaLabel = 'Drawer with active element';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n    active: true,\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const NavigationDrawerWithActiveElement = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button\n                        aria-current={tabContent.active ? 'page' : false}\n                        colorScheme=\"tertiary\"\n                        element={<a href={tabContent.href}>{tabContent.tabLabel}</a>}\n                      />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Navigation drawer with active element"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/navigation-drawer-with-icons",
            "github": "apps/workshop/src/examples/components/navigation-drawer/navigation-drawer-with-icons.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseTiny,\n  VisaStatisticsTiny,\n  VisaSettingsTiny,\n  VisaSecurityTiny,\n  VisaNotesTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'navigation-drawer-with-icons';\nconst navElAriaLabel = 'Drawer with icons';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n    icon: <VisaStatisticsTiny />,\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n    icon: <VisaSettingsTiny />,\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n    icon: <VisaSecurityTiny />,\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n    icon: <VisaNotesTiny />,\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n    icon: <VisaSupportTicketTiny />,\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const NavigationDrawerWithIcons = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          id={id}\n          ref={navDrawerRef}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={\n                          <a href={tabContent.href}>\n                            {tabContent.icon}\n                            {tabContent.tabLabel}\n                          </a>\n                        }\n                      />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Navigation drawer with icons"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/navigation-drawer-with-nested-elements",
            "github": "apps/workshop/src/examples/components/navigation-drawer/navigation-drawer-with-nested-elements.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'navigation-drawer-with-nested-elements';\nconst navElAriaLabel = 'Drawer with nested elements';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const NavigationDrawerWithNestedElements = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const [l1Label2Expanded, setL1Label2Expanded] = useState(false);\n  const [l1Label4Expanded, setL1Label4Expanded] = useState(false);\n  const [l2Label1Expanded, setL2Label1Expanded] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                <Tab>\n                  <UtilityFragment vMarginLeft={14}>\n                    <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 1</a>} />\n                  </UtilityFragment>\n                </Tab>\n                <Tab>\n                  <UtilityFragment vMarginLeft={14}>\n                    <Button\n                      aria-expanded={l1Label2Expanded}\n                      aria-controls={`${id}-l1-label2-sub-menu`}\n                      colorScheme=\"tertiary\"\n                      onClick={() => setL1Label2Expanded(!l1Label2Expanded)}\n                    >\n                      L1 label 2\n                      <TabSuffix element={l1Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </Button>\n                  </UtilityFragment>\n                  <UtilityFragment vHide={!l1Label2Expanded}>\n                    <Tabs orientation=\"vertical\" id={`${id}-l1-label2-sub-menu`} aria-hidden={!l1Label2Expanded}>\n                      <Tab>\n                        <UtilityFragment vMarginLeft={28}>\n                          <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L2 label 1</a>} />\n                        </UtilityFragment>\n                      </Tab>\n                      <Tab>\n                        <UtilityFragment vMarginLeft={28}>\n                          <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L2 label 2</a>} />\n                        </UtilityFragment>\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n                <Tab>\n                  <UtilityFragment vMarginLeft={14}>\n                    <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 3</a>} />\n                  </UtilityFragment>\n                </Tab>\n                <Tab>\n                  <UtilityFragment vMarginLeft={14}>\n                    <Button\n                      aria-expanded={l1Label4Expanded}\n                      aria-controls={`${id}-l1-label4-sub-menu`}\n                      colorScheme=\"tertiary\"\n                      onClick={() => setL1Label4Expanded(!l1Label4Expanded)}\n                    >\n                      L1 label 4\n                      <TabSuffix element={l1Label4Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </Button>\n                  </UtilityFragment>\n                  <UtilityFragment vHide={!l1Label4Expanded}>\n                    <Tabs orientation=\"vertical\" id={`${id}-l1-label4-sub-menu`} aria-hidden={!l1Label4Expanded}>\n                      <Tab>\n                        <UtilityFragment vMarginLeft={28}>\n                          <Button\n                            aria-expanded={l2Label1Expanded}\n                            aria-controls={`${id}-l2-label1-sub-menu`}\n                            colorScheme=\"tertiary\"\n                            onClick={() => setL2Label1Expanded(!l2Label1Expanded)}\n                          >\n                            L2 label 1\n                            <TabSuffix element={l2Label1Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                          </Button>\n                        </UtilityFragment>\n                        <UtilityFragment vHide={!l2Label1Expanded}>\n                          <Tabs orientation=\"vertical\" id={`${id}-l2-label1-sub-menu`} aria-hidden={!l2Label1Expanded}>\n                            <Tab>\n                              <UtilityFragment vMarginLeft={42}>\n                                <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L3 label 1</a>} />\n                              </UtilityFragment>\n                            </Tab>\n                            <Tab>\n                              <UtilityFragment vMarginLeft={42}>\n                                <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L3 label 2</a>} />\n                              </UtilityFragment>\n                            </Tab>\n                            <Tab>\n                              <UtilityFragment vMarginLeft={42}>\n                                <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L3 label 3</a>} />\n                              </UtilityFragment>\n                            </Tab>\n                          </Tabs>\n                        </UtilityFragment>\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n                <Tab>\n                  <UtilityFragment vMarginLeft={14}>\n                    <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 5</a>} />\n                  </UtilityFragment>\n                </Tab>\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Navigation drawer with nested elements"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/navigation-drawer-with-section-titles",
            "github": "apps/workshop/src/examples/components/navigation-drawer/navigation-drawer-with-section-titles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'navigation-drawer-with-section-titles';\nconst navElAriaLabel = 'Drawer with section titles';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const NavigationDrawerWithSectionTitles = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                <Tab>\n                  <UtilityFragment>\n                    <Tab sectionTitle tag=\"h2\">\n                      Section Title 1\n                    </Tab>\n                  </UtilityFragment>\n                  <Tabs orientation=\"vertical\">\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 1</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 2</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 3</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                  </Tabs>\n                </Tab>\n                <Tab>\n                  <UtilityFragment>\n                    <Tab sectionTitle tag=\"h2\">\n                      Section Title 2\n                    </Tab>\n                  </UtilityFragment>\n                  <Tabs orientation=\"vertical\">\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 4</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 5</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <UtilityFragment>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 6</a>} />\n                      </UtilityFragment>\n                    </Tab>\n                  </Tabs>\n                </Tab>\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Navigation drawer with section titles"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/navigation-drawer-with-nested-elements-and-section-titles",
            "github": "apps/workshop/src/examples/components/navigation-drawer/navigation-drawer-with-nested-elements-and-section-titles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'navigation-drawer-with-nested-elements-and-section-titles';\nconst navElAriaLabel = 'Drawer with nested elements and section titles';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const NavigationDrawerWithNestedElementsAndSectionTitles = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const [l1Label2Expanded, setL1Label2Expanded] = useState(false);\n  const [l2Label2Expanded, setL2Label2Expanded] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <UtilityFragment vGap={8}>\n                <Tabs orientation=\"vertical\">\n                  <Tab>\n                    <Tab sectionTitle tag=\"h2\">\n                      L1 Section Title 1\n                    </Tab>\n                    <Tabs orientation=\"vertical\">\n                      <Tab>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 1</a>} />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          aria-expanded={l1Label2Expanded}\n                          aria-controls={`${id}-l1-label2-sub-menu`}\n                          colorScheme=\"tertiary\"\n                          onClick={() => setL1Label2Expanded(!l1Label2Expanded)}\n                        >\n                          L1 label 2\n                          <TabSuffix element={l1Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </Button>\n                        <UtilityFragment vHide={!l1Label2Expanded}>\n                          <Tabs orientation=\"vertical\" id={`${id}-l1-label2-sub-menu`} tag=\"div\">\n                            <Tab sectionTitle tag=\"h3\">\n                              L2 Section Title 1\n                            </Tab>\n                            <Tabs orientation=\"vertical\">\n                              <Tab>\n                                <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L2 label 1</a>} />\n                              </Tab>\n                              <Tab>\n                                <Button\n                                  aria-expanded={l2Label2Expanded}\n                                  aria-controls={`${id}-l2-label2-sub-menu`}\n                                  colorScheme=\"tertiary\"\n                                  onClick={() => setL2Label2Expanded(!l2Label2Expanded)}\n                                >\n                                  L2 label 2\n                                  <TabSuffix\n                                    element={l2Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                                  />\n                                </Button>\n\n                                <UtilityFragment vHide={!l2Label2Expanded}>\n                                  <Tabs orientation=\"vertical\" id={`${id}-l2-label2-sub-menu`} tag=\"div\">\n                                    <Tab sectionTitle tag=\"h4\">\n                                      L3 Section Title 1\n                                    </Tab>\n                                    <Tabs orientation=\"vertical\">\n                                      <Tab>\n                                        <Button\n                                          colorScheme=\"tertiary\"\n                                          element={<a href=\"./navigation-drawer\">L3 label 1</a>}\n                                        />\n                                      </Tab>\n                                      <Tab>\n                                        <Button\n                                          colorScheme=\"tertiary\"\n                                          element={<a href=\"./navigation-drawer\">L3 label 2</a>}\n                                        />\n                                      </Tab>\n                                    </Tabs>\n                                  </Tabs>\n                                </UtilityFragment>\n                              </Tab>\n                            </Tabs>\n                          </Tabs>\n                        </UtilityFragment>\n                      </Tab>\n                    </Tabs>\n                  </Tab>\n                  <Tab>\n                    <Tab sectionTitle tag=\"h2\">\n                      L1 Section Title 2\n                    </Tab>\n                    <Tabs orientation=\"vertical\">\n                      <Tab>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 3</a>} />\n                      </Tab>\n                      <Tab>\n                        <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 4</a>} />\n                      </Tab>\n                    </Tabs>\n                  </Tab>\n                </Tabs>\n              </UtilityFragment>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Navigation drawer with nested elements and section titles"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/alternate-navigation-drawer",
            "github": "apps/workshop/src/examples/components/navigation-drawer/alternate-navigation-drawer.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-navigation-drawer';\nconst navElAriaLabel = 'Alternate drawer';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const AlternateNavigationDrawer = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            alternate\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button colorScheme=\"tertiary\" element={<a href={tabContent.href}>{tabContent.tabLabel}</a>} />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Alternate navigation drawer"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/alternate-navigation-drawer-with-active-element",
            "github": "apps/workshop/src/examples/components/navigation-drawer/alternate-navigation-drawer-with-active-element.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaAccountTiny, VisaChevronDownTiny, VisaChevronUpTiny, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-navigation-drawer-with-active-element';\nconst navElAriaLabel = 'Alternate drawer with active element';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n    active: true,\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const AlternateNavigationDrawerWithActiveElement = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            alternate\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button\n                        aria-current={tabContent.active ? 'page' : false}\n                        colorScheme=\"tertiary\"\n                        element={<a href={tabContent.href}>{tabContent.tabLabel}</a>}\n                      />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Alternate navigation drawer with active element"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Default navigation drawers",
          "url": {
            "iframe": "components/navigation-drawer/alternate-navigation-drawer-with-icons",
            "github": "apps/workshop/src/examples/components/navigation-drawer/alternate-navigation-drawer-with-icons.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseTiny,\n  VisaStatisticsTiny,\n  VisaSettingsTiny,\n  VisaSecurityTiny,\n  VisaNotesTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState, useRef, type CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-navigation-drawer-with-icons';\nconst navElAriaLabel = 'Alternate drawer with icons';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './navigation-drawer',\n    icon: <VisaStatisticsTiny />,\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './navigation-drawer',\n    icon: <VisaSettingsTiny />,\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './navigation-drawer',\n    icon: <VisaSecurityTiny />,\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './navigation-drawer',\n    icon: <VisaNotesTiny />,\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './navigation-drawer',\n    icon: <VisaSupportTicketTiny />,\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './navigation-drawer',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './navigation-drawer',\n  },\n];\n\nexport const AlternateNavigationDrawerWithIcons = () => {\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const navDrawerRef = useRef<HTMLDialogElement>(null);\n\n  return (\n    <>\n      <UtilityFragment vMargin={10}>\n        <Button onClick={() => navDrawerRef.current?.showModal()}>Open drawer</Button>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginHorizontal={0}>\n        <Panel<'dialog'>\n          aria-modal=\"true\"\n          ref={navDrawerRef}\n          id={id}\n          tag=\"dialog\"\n          style={\n            {\n              '--v-panel-inline-size': 'initial',\n            } as CSSProperties\n          }\n        >\n          <Nav\n            alternate\n            drawer\n            orientation=\"vertical\"\n            tag=\"div\"\n            style={\n              {\n                inlineSize: '242px',\n              } as CSSProperties\n            }\n          >\n            <UtilityFragment vMarginRight={4} vMarginLeft=\"auto\">\n              <Button\n                aria-label=\"Close\"\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => navDrawerRef.current?.close()}\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment\n              vFlex\n              vFlexCol\n              vGap={12}\n              vMarginTop={4}\n              vMarginRight={16}\n              vMarginBottom={16}\n              vMarginLeft={24}\n            >\n              <Link\n                aria-label=\"Visa Application Name Home\"\n                href=\"https://www.visa.com\"\n                id={`${id}-home-link`}\n                noUnderline\n                style={{ backgroundColor: 'transparent' }}\n              >\n                <VisaLogo />\n                <NavAppName>\n                  <Typography variant=\"subtitle-1\">Application Name</Typography>\n                </NavAppName>\n              </Link>\n            </UtilityFragment>\n            <nav aria-label={navElAriaLabel}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <UtilityFragment vMarginLeft={14}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={\n                          <a href={tabContent.href}>\n                            {tabContent.icon}\n                            {tabContent.tabLabel}\n                          </a>\n                        }\n                      />\n                    </UtilityFragment>\n                  </Tab>\n                ))}\n              </Tabs>\n            </nav>\n            <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n              <Divider dividerType=\"decorative\" />\n              <Tab tag=\"div\">\n                <Button\n                  aria-expanded={accountTabOpen}\n                  aria-controls={`${id}-account-sub-menu`}\n                  aria-label=\"Alex Miller\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  onClick={() => setAccountTabOpen(!accountTabOpen)}\n                >\n                  <VisaAccountTiny />\n                  Alex Miller\n                  <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                </Button>\n                <UtilityFragment vHide={!accountTabOpen}>\n                  <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                    {accountSubItems.map(accountSubItem => (\n                      <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </Tab>\n            </Utility>\n          </Nav>\n        </Panel>\n      </UtilityFragment>\n    </>\n  );\n};\n"
          },
          "name": "Alternate navigation drawer with icons"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Nav",
          "selector": "<Nav />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Menu or panel at the top or next to page content that links to important pages or features."
        },
        {
          "order": 2,
          "name": "tabs",
          "type": "related",
          "selector": "<Tabs />",
          "description": ""
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Nav",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate"
          }
        },
        {
          "name": "drawer",
          "section": "Nav",
          "data": {
            "name": "drawer",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Drawer"
          }
        },
        {
          "name": "orientation",
          "section": "Nav",
          "data": {
            "name": "orientation",
            "type": "\"horizontal\" , \"vertical\"",
            "default": "",
            "required": "false",
            "description": "Orientation"
          }
        },
        {
          "name": "tag",
          "section": "Nav",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "nav",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "pagination",
      "version": "0.0.1",
      "description": "Set of links used to navigate content split across multiple pages.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default paginations",
          "description": "",
          "order": 1
        },
        {
          "name": "Slim paginations",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom paginations",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default paginations",
          "url": {
            "iframe": "components/pagination/one-digit-pagination",
            "github": "apps/workshop/src/examples/components/pagination/one-digit-pagination.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Pagination, PaginationOverflow } from '@visa/nova-react';\n\nexport const OneDigitPagination = () => {\n  return (\n    <nav aria-label=\"1 digit pagination\" role=\"navigation\">\n      <Pagination className=\"v-align-items-center v-gap-4\">\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to first page\" buttonSize=\"small\" colorScheme=\"tertiary\" disabled iconButton>\n            <VisaArrowStartTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to previous page\" buttonSize=\"small\" colorScheme=\"tertiary\" disabled iconButton>\n            <VisaChevronLeftTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-current=\"true\" aria-label=\"Page 1\" colorScheme=\"tertiary\">\n            1\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Page 2\" colorScheme=\"tertiary\">\n            2\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Page 3\" colorScheme=\"tertiary\">\n            3\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 4\" colorScheme=\"tertiary\">\n            4\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 5\" colorScheme=\"tertiary\">\n            5\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 6\" colorScheme=\"tertiary\">\n            6\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 7\" colorScheme=\"tertiary\">\n            7\n          </Button>\n        </li>\n        <PaginationOverflow className=\"v-flex v-align-items-center v-mobile-container-hide\">\n          <VisaOptionHorizontalTiny />\n        </PaginationOverflow>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 100\" colorScheme=\"tertiary\">\n            100\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to next page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaChevronRightTiny rtl />\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to last page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaArrowEndTiny rtl />\n          </Button>\n        </li>\n      </Pagination>\n    </nav>\n  );\n};\n"
          },
          "name": "Default pagination with first page selected"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default paginations",
          "url": {
            "iframe": "components/pagination/two-digit-pagination",
            "github": "apps/workshop/src/examples/components/pagination/two-digit-pagination.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Pagination, PaginationOverflow } from '@visa/nova-react';\n\nexport const TwoDigitPagination = () => {\n  return (\n    <nav aria-label=\"2 digit pagination\" role=\"navigation\">\n      <Pagination className=\"v-align-items-center v-gap-4\">\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to first page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaArrowStartTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to previous page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaChevronLeftTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Page 1\" className=\"v-mobile-container-hide\" colorScheme=\"tertiary\">\n            1\n          </Button>\n        </li>\n        <PaginationOverflow className=\"v-flex v-align-items-center v-mobile-container-hide\">\n          <VisaOptionHorizontalTiny />\n        </PaginationOverflow>\n        <li>\n          <Button aria-label=\"Page 4\" colorScheme=\"tertiary\">\n            4\n          </Button>\n        </li>\n        <li>\n          <Button aria-current=\"true\" aria-label=\"Page 5\" colorScheme=\"tertiary\">\n            5\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Page 6\" colorScheme=\"tertiary\">\n            6\n          </Button>\n        </li>\n        <PaginationOverflow className=\"v-flex v-align-items-center v-mobile-container-hide\">\n          <VisaOptionHorizontalTiny />\n        </PaginationOverflow>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 100\" colorScheme=\"tertiary\">\n            100\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to next page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaChevronRightTiny rtl />\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to last page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaArrowEndTiny rtl />\n          </Button>\n        </li>\n      </Pagination>\n    </nav>\n  );\n};\n"
          },
          "name": "Default pagination with middle page selected"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default paginations",
          "url": {
            "iframe": "components/pagination/last-page-selected",
            "github": "apps/workshop/src/examples/components/pagination/last-page-selected.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Pagination, PaginationOverflow } from '@visa/nova-react';\n\nexport const LastPageSelected = () => {\n  return (\n    <nav aria-label=\"1 digit pagination\" role=\"navigation\">\n      <Pagination className=\"v-align-items-center v-gap-4\">\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to first page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaArrowStartTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to previous page\" buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n            <VisaChevronLeftTiny rtl />\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Page 1\" colorScheme=\"tertiary\">\n            1\n          </Button>\n        </li>\n        <PaginationOverflow className=\"v-flex v-align-items-center v-mobile-container-hide\">\n          <VisaOptionHorizontalTiny />\n        </PaginationOverflow>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 96\" colorScheme=\"tertiary\">\n            96\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 97\" colorScheme=\"tertiary\">\n            97\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 98\" colorScheme=\"tertiary\">\n            98\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 99\" colorScheme=\"tertiary\">\n            99\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Page 100\" aria-current=\"true\" colorScheme=\"tertiary\">\n            100\n          </Button>\n        </li>\n        <li>\n          <Button aria-label=\"Go to next page\" buttonSize=\"small\" colorScheme=\"tertiary\" disabled iconButton>\n            <VisaChevronRightTiny rtl />\n          </Button>\n        </li>\n        <li className=\"v-mobile-container-hide\">\n          <Button aria-label=\"Go to last page\" buttonSize=\"small\" colorScheme=\"tertiary\" disabled iconButton>\n            <VisaArrowEndTiny rtl />\n          </Button>\n        </li>\n      </Pagination>\n    </nav>\n  );\n};\n"
          },
          "name": "Default pagination with last page selected"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Slim paginations",
          "url": {
            "iframe": "components/pagination/slim-pagination",
            "github": "apps/workshop/src/examples/components/pagination/slim-pagination.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronLeftTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { Button, Pagination, usePagination } from '@visa/nova-react';\n\nexport const SlimPagination = () => {\n  const { pages, selectedPage, isFirstPage, isLastPage, onPageChange, onPreviousPage, onNextPage } = usePagination({\n    totalPages: 10,\n    compact: true,\n    blockMaxLength: 5,\n  });\n\n  return (\n    <nav aria-label=\"pagination\">\n      <Pagination className=\"v-align-items-center v-gap-4\">\n        <li>\n          <Button\n            aria-label=\"Go to previous page\"\n            buttonSize=\"small\"\n            colorScheme=\"tertiary\"\n            disabled={isFirstPage}\n            iconButton\n            onClick={onPreviousPage}\n          >\n            <VisaChevronLeftTiny rtl />\n          </Button>\n        </li>\n        {pages.map(page => (\n          <li key={page} className=\"v-mobile-container-hide\">\n            <Button\n              aria-current={page === selectedPage ? 'true' : undefined}\n              aria-label={`Page ${page}`}\n              colorScheme=\"tertiary\"\n              onClick={() => onPageChange(+page)}\n            >\n              {page}\n            </Button>\n          </li>\n        ))}\n        <li>\n          <Button\n            aria-label=\"Go to next page\"\n            buttonSize=\"small\"\n            colorScheme=\"tertiary\"\n            disabled={isLastPage}\n            iconButton\n            onClick={onNextPage}\n          >\n            <VisaChevronRightTiny rtl />\n          </Button>\n        </li>\n      </Pagination>\n    </nav>\n  );\n};\n"
          },
          "name": "Default slim pagination"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Custom paginations",
          "url": {
            "iframe": "components/pagination/table-pagination",
            "github": "apps/workshop/src/examples/components/pagination/table-pagination.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronDownTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  InputContainer,\n  InputControl,\n  InputMessage,\n  Label,\n  Pagination,\n  PaginationOverflow,\n  Select,\n  Utility,\n  UtilityFragment,\n  calculatePagesFromTo,\n  calculateTotalPages,\n  usePagination,\n} from '@visa/nova-react';\nimport { useState, type CSSProperties, type FormEvent } from 'react';\n\nconst totalItems = 100;\n\nexport const TablePagination = () => {\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const {\n    isFirstPage,\n    isLastPage,\n    onFirstPage,\n    onLastPage,\n    onNextPage,\n    onPageChange,\n    onPreviousPage,\n    pages,\n    selectedPage,\n  } = usePagination({ totalPages });\n\n  const { from, to } = calculatePagesFromTo(totalItems, itemsPerPage, selectedPage);\n\n  const onItemsPerPageChange = (event: FormEvent<HTMLSelectElement>) => {\n    onFirstPage();\n    setItemsPerPage(+event.currentTarget.value);\n  };\n\n  return (\n    <Utility vAlignItems=\"center\" vFlex vFlexRow vFlexWrapReverse vGap={10} vJustifyContent=\"between\">\n      <Utility\n        style={{ textWrap: 'nowrap' } as CSSProperties}\n        tag=\"fieldset\"\n        vAlignItems=\"center\"\n        vFlex\n        vFlexRow\n        vGap={12}\n      >\n        <UtilityFragment vFlexShrink0>\n          <Label htmlFor=\"select-items-per-page\">Items Per Page</Label>\n        </UtilityFragment>\n        <InputContainer>\n          <Select\n            id=\"select-items-per-page\"\n            name=\"select-items-per-page\"\n            onChange={onItemsPerPageChange}\n            value={itemsPerPage}\n          >\n            <option value=\"10\">10</option>\n            <option value=\"20\">20</option>\n            <option value=\"50\">50</option>\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n        <InputMessage id=\"select-default-message\">{`${from} - ${to} of ${totalItems}`}</InputMessage>\n      </Utility>\n      <UtilityFragment>\n        <nav aria-label=\"table pagination\" role=\"navigation\">\n          <UtilityFragment vAlignItems=\"center\" vGap={4}>\n            <Pagination>\n              <li>\n                <Button\n                  aria-label=\"Go to first page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isFirstPage}\n                  iconButton\n                  onClick={onFirstPage}\n                >\n                  <VisaArrowStartTiny rtl />\n                </Button>\n              </li>\n              <li>\n                <Button\n                  aria-label=\"Go to previous page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isFirstPage}\n                  iconButton\n                  onClick={onPreviousPage}\n                >\n                  <VisaChevronLeftTiny rtl />\n                </Button>\n              </li>\n              {pages.map((pageNumber, index) =>\n                pageNumber === -1 ? (\n                  <UtilityFragment key={`table-pagination-ellipse-${index}`} vAlignItems=\"center\" vFlex>\n                    <PaginationOverflow>\n                      <VisaOptionHorizontalTiny />\n                    </PaginationOverflow>\n                  </UtilityFragment>\n                ) : (\n                  <li key={`table-pagination-page-${pageNumber}`}>\n                    <Button\n                      aria-current={selectedPage === pageNumber}\n                      aria-label={`Page ${pageNumber}`}\n                      colorScheme=\"tertiary\"\n                      onClick={() => onPageChange(pageNumber as number)}\n                    >\n                      {pageNumber}\n                    </Button>\n                  </li>\n                )\n              )}\n              <li>\n                <Button\n                  aria-label=\"Go to next page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isLastPage}\n                  iconButton\n                  onClick={onNextPage}\n                >\n                  <VisaChevronRightTiny rtl />\n                </Button>\n              </li>\n              <li>\n                <Button\n                  aria-label=\"Go to last page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isLastPage}\n                  iconButton\n                  onClick={onLastPage}\n                >\n                  <VisaArrowEndTiny rtl />\n                </Button>\n              </li>\n            </Pagination>\n          </UtilityFragment>\n        </nav>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Pagination for tables"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Custom paginations",
          "url": {
            "iframe": "components/pagination/reusable",
            "github": "apps/workshop/src/examples/components/pagination/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronDownTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  calculatePagesFromTo,\n  calculateTotalPages,\n  InputContainer,\n  InputControl,\n  InputMessage,\n  Label,\n  Pagination,\n  PaginationOverflow,\n  Select,\n  usePagination,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type CSSProperties, type FormEvent, useEffect, useId, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Nova Pagination Component Props\nexport interface NovaPaginationProps {\n  'aria-label'?: string;\n  blockMaxLength?: number;\n  compact?: boolean;\n  disabled?: boolean;\n  id?: string;\n  inline?: boolean;\n  itemsPerPage?: number;\n  itemsPerPageOptions?: number[];\n  onItemsPerPageChange?: (itemsPerPage: number) => void;\n  onPageChange?: (page: number) => void;\n  page?: number;\n  selectLabel?: string;\n  showItemsPerPage?: boolean;\n  showPageRange?: boolean;\n  totalItems?: number;\n}\n\n// Main Nova Pagination Component\nexport const NovaPagination = ({\n  'aria-label': ariaLabel = 'Pagination for table',\n  blockMaxLength,\n  compact = false,\n  disabled = false,\n  id: idProp,\n  inline = true,\n  itemsPerPage: itemsPerPageProp = 10,\n  itemsPerPageOptions = [5, 10, 15, 20],\n  onItemsPerPageChange: onItemsPerPageChangeProp,\n  onPageChange: onPageChangeProp,\n  page,\n  selectLabel = 'Results per page',\n  showItemsPerPage = true,\n  showPageRange = true,\n  totalItems = 1,\n  ...remainingProps\n}: NovaPaginationProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n  const [itemsPerPageControlled, setItemsPerPageControlled] = useState(10);\n\n  const itemsPerPage = itemsPerPageProp ?? itemsPerPageControlled;\n  const setItemsPerPage = onItemsPerPageChangeProp ?? setItemsPerPageControlled;\n\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const {\n    isFirstPage,\n    isLastPage,\n    onFirstPage,\n    onLastPage,\n    onNextPage,\n    onPageChange,\n    onPreviousPage,\n    pages,\n    selectedPage,\n  } = usePagination({\n    blockMaxLength,\n    compact,\n    setSelectedPage: onPageChangeProp,\n    selectedPage: page,\n    totalPages,\n  });\n\n  const { from, to } = calculatePagesFromTo(totalItems, itemsPerPage, selectedPage);\n\n  const onItemsPerPageChange = (event: FormEvent<HTMLSelectElement>) => {\n    onFirstPage();\n    setItemsPerPage(+event.currentTarget.value);\n  };\n\n  useEffect(() => {\n    onFirstPage();\n  }, [itemsPerPage, totalItems]);\n\n  return (\n    <Utility\n      vAlignItems=\"center\"\n      vFlex\n      vFlexRow\n      vFlexWrapReverse\n      vGap={10}\n      vJustifyContent=\"between\"\n      {...remainingProps}\n    >\n      {(showItemsPerPage || showPageRange) && (\n        <Utility\n          style={{ textWrap: 'nowrap' } as CSSProperties}\n          tag=\"fieldset\"\n          vAlignItems={inline ? 'center' : undefined}\n          vFlex\n          vFlexRow={inline}\n          vFlexCol={!inline}\n          vGap={8}\n          vFlexWrap\n        >\n          {showItemsPerPage && (\n            <>\n              <UtilityFragment vFlexShrink0>\n                <Label htmlFor={`${id}-select`} variant=\"label-large\">\n                  {selectLabel}\n                </Label>\n              </UtilityFragment>\n              <InputContainer style={{ flexBasis: inline ? 'max-content' : undefined }}>\n                <Select\n                  aria-describedby={showPageRange ? `${id}-select-message` : undefined}\n                  disabled={disabled}\n                  id={`${id}-select`}\n                  name={`${id}-select`}\n                  onChange={onItemsPerPageChange}\n                  value={itemsPerPage}\n                >\n                  {itemsPerPageOptions.map(option => (\n                    <option key={`${id}-items-per-page-option-${option}`} value={option}>\n                      {option}\n                    </option>\n                  ))}\n                </Select>\n                <InputControl>\n                  <VisaChevronDownTiny />\n                </InputControl>\n              </InputContainer>\n            </>\n          )}\n          {showPageRange && (\n            <InputMessage\n              id={`${id}-select-message`}\n              variant=\"body-2\"\n            >{`${from} - ${to} of ${totalItems}`}</InputMessage>\n          )}\n        </Utility>\n      )}\n      <UtilityFragment>\n        <nav aria-label={ariaLabel} role=\"navigation\">\n          <UtilityFragment vAlignItems=\"center\" vGap={4} vFlex vFlexWrap>\n            <Pagination>\n              {!compact && (\n                <li>\n                  <Button\n                    aria-label=\"Go to first page\"\n                    buttonSize=\"small\"\n                    colorScheme=\"tertiary\"\n                    disabled={isFirstPage || disabled}\n                    iconButton\n                    onClick={onFirstPage}\n                  >\n                    <VisaArrowStartTiny rtl />\n                  </Button>\n                </li>\n              )}\n              <li>\n                <Button\n                  aria-label=\"Go to previous page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isFirstPage || disabled}\n                  iconButton\n                  onClick={onPreviousPage}\n                >\n                  <VisaChevronLeftTiny rtl />\n                </Button>\n              </li>\n              {pages.map((pageNumber, index) =>\n                pageNumber === -1 ? (\n                  <UtilityFragment key={`table-pagination-ellipse-${index}`} vAlignItems=\"center\" vFlex>\n                    <PaginationOverflow>\n                      <VisaOptionHorizontalTiny />\n                    </PaginationOverflow>\n                  </UtilityFragment>\n                ) : (\n                  <li key={`table-pagination-page-${pageNumber}`}>\n                    <Button\n                      aria-current={selectedPage === pageNumber}\n                      aria-label={`Page ${pageNumber}`}\n                      colorScheme=\"tertiary\"\n                      disabled={disabled}\n                      onClick={() => onPageChange(pageNumber as number)}\n                    >\n                      {pageNumber}\n                    </Button>\n                  </li>\n                )\n              )}\n              <li>\n                <Button\n                  aria-label=\"Go to next page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isLastPage || disabled}\n                  iconButton\n                  onClick={onNextPage}\n                >\n                  <VisaChevronRightTiny rtl />\n                </Button>\n              </li>\n              {!compact && (\n                <li>\n                  <Button\n                    aria-label=\"Go to last page\"\n                    buttonSize=\"small\"\n                    colorScheme=\"tertiary\"\n                    disabled={isLastPage || disabled}\n                    iconButton\n                    onClick={onLastPage}\n                  >\n                    <VisaArrowEndTiny rtl />\n                  </Button>\n                </li>\n              )}\n            </Pagination>\n          </UtilityFragment>\n        </nav>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n\n// export default NovaPagination;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  compact: boolean;\n  disabled: boolean;\n  inline: boolean;\n  showItemsPerPage: boolean;\n  showPageRange: boolean;\n  totalItems: number;\n}\n\n// Demo Component\nexport const NovaPaginationDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    compact: false,\n    disabled: false,\n    inline: true,\n    showItemsPerPage: true,\n    showPageRange: true,\n    totalItems: 100,\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean | number) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <NovaPagination\n        blockMaxLength={customizations.compact ? 5 : undefined}\n        compact={customizations.compact}\n        disabled={customizations.disabled}\n        inline={customizations.inline}\n        showItemsPerPage={customizations.showItemsPerPage}\n        showPageRange={customizations.showPageRange}\n        totalItems={customizations.totalItems}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Total items\"\n                onChange={e => handleInputChange('totalItems', Number(e.target.value) || 100)}\n                type=\"number\"\n                value={formValues.totalItems.toString()}\n              />\n\n              <NovaCheckbox\n                label=\"Compact\"\n                checked={formValues.compact}\n                onChange={e => handleInputChange('compact', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Inline\"\n                checked={formValues.inline}\n                onChange={e => handleInputChange('inline', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Show items per page\"\n                checked={formValues.showItemsPerPage}\n                onChange={e => handleInputChange('showItemsPerPage', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Show page range\"\n                checked={formValues.showPageRange}\n                onChange={e => handleInputChange('showPageRange', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaPaginationDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable pagination"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Pagination",
          "selector": "<Pagination />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Set of links used to navigate content split across multiple pages."
        },
        {
          "order": 2,
          "name": "Paginationoverflow",
          "selector": "<PaginationOverflow />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Element to show hidden elements within pagination component, usually used with ellipsis icon."
        },
        {
          "order": 3,
          "name": "usePagination",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to manage pagination events, state, and visible page blocks. Supports both controlled and uncontrolled usage."
        }
      ],
      "properties": [
        {
          "name": "orientation",
          "section": "Pagination",
          "data": {
            "name": "orientation",
            "type": "\"horizontal\" , \"vertical\"",
            "default": "horizontal",
            "required": "false",
            "description": "Layout orientation - automatically applies flex-row (horizontal) or flex-col (vertical)"
          }
        },
        {
          "name": "tag",
          "section": "Pagination",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "ul",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Paginationoverflow",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "li",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "panel",
      "version": "0.0.1",
      "description": "Collapsible or persistent containers used to present supplementary information.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default panels",
          "description": "",
          "order": 1
        },
        {
          "name": "Expandable panels",
          "description": "",
          "order": 2
        },
        {
          "name": "Tabbed panels",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default panels",
          "url": {
            "iframe": "components/panel/modal-panel",
            "github": "apps/workshop/src/examples/components/panel/modal-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'modal-panel-default';\n\nexport const ModalPanel = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open modal panel</Button>\n      <Panel<'dialog'>\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        aria-modal=\"true\"\n        id={id}\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n        ref={ref}\n        tag=\"dialog\"\n      >\n        <PanelContent>\n          <Utility element={<PanelHeader />} vFlex vFlexRow vJustifyContent=\"between\" vGap={4}>\n            <Typography id={`${id}-title`} tag=\"h2\" variant=\"headline-3\">\n              Panel title\n            </Typography>\n            <Button\n              aria-label=\"Close panel\"\n              buttonSize=\"small\"\n              className=\"-v-mt-3 -v-mr-8\"\n              colorScheme=\"tertiary\"\n              iconButton\n              onClick={() => ref.current?.close()}\n              subtle\n            >\n              <VisaCloseTiny />\n            </Button>\n          </Utility>\n          <PanelBody>\n            <Typography id={`${id}-description`} tag=\"h3\" variant=\"subtitle-2\">\n              Panel subtitle\n            </Typography>\n            <Typography>\n              This is required text that can be used to describe the panel title and subtitle in more detail.\n            </Typography>\n          </PanelBody>\n        </PanelContent>\n      </Panel>\n    </>\n  );\n};\n"
          },
          "name": "Modal panel"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default panels",
          "url": {
            "iframe": "components/panel/default-panel",
            "github": "apps/workshop/src/examples/components/panel/default-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultPanel = () => {\n  return (\n    <Utility vFlex>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <Panel style={{ minInlineSize: 'initial' }}>\n          <PanelContent>\n            <Utility element={<PanelHeader />} vFlex vFlexRow vGap={4} vJustifyContent=\"between\">\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n              <Button\n                aria-label=\"Close panel\"\n                buttonSize=\"small\"\n                className=\"-v-mt-3 -v-mr-8\"\n                colorScheme=\"tertiary\"\n                iconButton\n                subtle\n              >\n                <VisaCloseTiny />\n              </Button>\n            </Utility>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default responsive panel"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable panels",
          "url": {
            "iframe": "components/panel/expandable-panel",
            "github": "apps/workshop/src/examples/components/panel/expandable-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelToggle,\n  Typography,\n  useFocusTrap,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const ModalExpandablePanel = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <Utility vFlex>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded=\"false\"\n          aria-label=\"Open panel\"\n          buttonSize=\"large\"\n          iconButton\n          iconTwoColor\n          onClick={() => ref.current?.showModal()}\n        >\n          <VisaMediaRewindTiny rtl />\n        </PanelToggle>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginLeft=\"auto\">\n        <Panel<'dialog'>\n          expandable\n          onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n          ref={ref}\n          style={{ height: 400 }}\n          tag=\"dialog\"\n        >\n          <PanelToggle\n            aria-expanded=\"true\"\n            aria-label=\"Close panel\"\n            buttonSize=\"large\"\n            iconButton\n            iconTwoColor\n            onClick={() => ref.current?.close()}\n          >\n            <VisaMediaFastForwardTiny rtl />\n          </PanelToggle>\n\n          <PanelContent>\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Modal expandable panel"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable panels",
          "url": {
            "iframe": "components/panel/expandable-responsive-panel",
            "github": "apps/workshop/src/examples/components/panel/expandable-responsive-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelToggle,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const ExpandableResponsivePanel = () => {\n  const [open, setOpen] = useState(true);\n\n  return (\n    <Utility vFlex style={{ minBlockSize: 200 }}>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded={open}\n          aria-label={open ? 'Close panel' : 'Open panel'}\n          buttonSize=\"large\"\n          iconButton\n          iconTwoColor\n          onClick={() => setOpen(open ? false : true)}\n        >\n          {open ? <VisaMediaFastForwardTiny rtl /> : <VisaMediaRewindTiny rtl />}\n        </PanelToggle>\n      </UtilityFragment>\n\n      {open && (\n        <Panel expandable style={{ minInlineSize: 'initial' }}>\n          <PanelContent>\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Responsive expanded panel"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable panels",
          "url": {
            "iframe": "components/panel/expandable-panel-secondary",
            "github": "apps/workshop/src/examples/components/panel/expandable-panel-secondary.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelToggle,\n  Typography,\n  useFocusTrap,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const SecondaryModalExpandablePanel = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <Utility vFlex>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded={false}\n          aria-label=\"Open panel\"\n          buttonSize=\"large\"\n          colorScheme=\"secondary\"\n          iconButton\n          onClick={() => ref.current?.showModal()}\n        >\n          <VisaMediaRewindTiny rtl />\n        </PanelToggle>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginLeft=\"auto\">\n        <Panel<'dialog'>\n          expandable\n          onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n          ref={ref}\n          style={{ height: 400 }}\n          tag=\"dialog\"\n        >\n          <PanelToggle\n            aria-expanded=\"true\"\n            aria-label=\"Close panel\"\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            iconButton\n            onClick={() => ref.current?.close()}\n          >\n            <VisaMediaFastForwardTiny rtl />\n          </PanelToggle>\n\n          <PanelContent>\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Modal expandable panel with secondary button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable panels",
          "url": {
            "iframe": "components/panel/expandable-panel-skrim",
            "github": "apps/workshop/src/examples/components/panel/expandable-panel-skrim.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelToggle,\n  Typography,\n  useFocusTrap,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const ModalExpandablePanelWithSkrim = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <Utility vFlex>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded={false}\n          aria-label=\"Open panel\"\n          buttonSize=\"large\"\n          iconButton\n          iconTwoColor\n          onClick={() => ref.current?.showModal()}\n        >\n          <VisaMediaRewindTiny rtl />\n        </PanelToggle>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginLeft=\"auto\">\n        <Panel<'dialog'>\n          expandable\n          onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n          ref={ref}\n          skrim\n          style={{ height: 400 }}\n          tag=\"dialog\"\n        >\n          <PanelToggle\n            aria-expanded=\"true\"\n            aria-label=\"Close panel\"\n            buttonSize=\"large\"\n            iconButton\n            iconTwoColor\n            onClick={() => ref.current?.close()}\n          >\n            <VisaMediaFastForwardTiny rtl />\n          </PanelToggle>\n\n          <PanelContent>\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Modal expandable panel with skrim"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Tabbed panels",
          "url": {
            "iframe": "components/panel/tabbed-expandable-panel",
            "github": "apps/workshop/src/examples/components/panel/tabbed-expandable-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelToggle,\n  Typography,\n  useFocusTrap,\n  Utility,\n  PanelTabs,\n  Button,\n  UtilityFragment,\n  Tab,\n  Divider,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'tabbed-expandable-panel-example';\n\nconst tabs = ['FAQ', 'Chat', 'Contact'];\n\nexport const TabbedModalExpandablePanel = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n  const [selectedTabIndex, setSelectedTabIndex] = useState(0);\n\n  return (\n    <Utility vFlex>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded={false}\n          aria-label=\"Open panel\"\n          buttonSize=\"large\"\n          iconButton\n          iconTwoColor\n          onClick={() => ref.current?.showModal()}\n        >\n          <VisaMediaRewindTiny rtl />\n        </PanelToggle>\n      </UtilityFragment>\n\n      <UtilityFragment vMarginLeft=\"auto\">\n        <Panel<'dialog'>\n          expandable\n          onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n          ref={ref}\n          style={{ height: 400 }}\n          tag=\"dialog\"\n        >\n          <PanelToggle\n            aria-expanded=\"true\"\n            aria-label=\"Close panel\"\n            buttonSize=\"large\"\n            iconButton\n            iconTwoColor\n            onClick={() => ref.current?.close()}\n          >\n            <VisaMediaFastForwardTiny rtl />\n          </PanelToggle>\n\n          <PanelContent>\n            <PanelTabs orientation=\"horizontal\" role=\"tablist\">\n              {tabs.map((tab, index) => (\n                <Tab key={id + tab} role=\"none\">\n                  <Button\n                    aria-label={tab}\n                    aria-selected={index === selectedTabIndex}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setSelectedTabIndex(index)}\n                    role=\"tab\"\n                  >\n                    {tab}\n                  </Button>\n                </Tab>\n              ))}\n            </PanelTabs>\n            <Divider dividerType=\"decorative\" />\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Tabbed modal expandable panel"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Tabbed panels",
          "url": {
            "iframe": "components/panel/tabbed-expandable-responsive-panel",
            "github": "apps/workshop/src/examples/components/panel/tabbed-expandable-responsive-panel.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelHeader,\n  PanelTabs,\n  PanelToggle,\n  Tab,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'tabbed-expandable-responsive-panel-example';\n\nconst tabs = ['FAQ', 'Chat', 'Contact'];\n\nexport const TabbedExpandableResponsivePanel = () => {\n  const [open, setOpen] = useState(true);\n  const [selectedTabIndex, setSelectedTabIndex] = useState(0);\n\n  return (\n    <Utility vFlex style={{ minBlockSize: 200 }}>\n      <UtilityFragment vMarginLeft=\"auto\">\n        <PanelToggle\n          aria-expanded={open}\n          aria-label={open ? 'Close panel' : 'Open panel'}\n          buttonSize=\"large\"\n          iconButton\n          iconTwoColor\n          onClick={() => setOpen(open ? false : true)}\n        >\n          {open ? <VisaMediaFastForwardTiny rtl /> : <VisaMediaRewindTiny rtl />}\n        </PanelToggle>\n      </UtilityFragment>\n\n      {open && (\n        <Panel expandable>\n          <PanelContent>\n            <PanelTabs orientation=\"horizontal\" role=\"tablist\">\n              {tabs.map((tab, index) => (\n                <Tab key={id + tab} role=\"none\">\n                  <Button\n                    aria-label={tab}\n                    aria-selected={index === selectedTabIndex}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setSelectedTabIndex(index)}\n                    role=\"tab\"\n                  >\n                    {tab}\n                  </Button>\n                </Tab>\n              ))}\n            </PanelTabs>\n            <Divider dividerType=\"decorative\" />\n            <PanelHeader>\n              <Typography tag=\"h2\" variant=\"headline-3\">\n                Panel title\n              </Typography>\n            </PanelHeader>\n            <PanelBody>\n              <Typography tag=\"h3\" variant=\"subtitle-2\">\n                Panel subtitle\n              </Typography>\n              <Typography>\n                This is required text that can be used to describe the panel title and subtitle in more detail.\n              </Typography>\n            </PanelBody>\n          </PanelContent>\n        </Panel>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Tabbed responsive expanded panel"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Panel",
          "selector": "<Panel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Collapsible or persistent containers used to present supplementary information."
        },
        {
          "order": 2,
          "name": "Panelbody",
          "selector": "<PanelBody />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for panel body elements."
        },
        {
          "order": 3,
          "name": "Panelcontent",
          "selector": "<PanelContent />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for all panel content, included heading and body."
        },
        {
          "order": 4,
          "name": "Panelheader",
          "selector": "<PanelHeader />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for panel heading."
        },
        {
          "order": 5,
          "name": "Paneltoggle",
          "selector": "<PanelToggle />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Button used with a panel component to hide or show the panel."
        },
        {
          "order": 6,
          "name": "useFocusTrap",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to trap focus inside a container."
        }
      ],
      "properties": [
        {
          "name": "expandable",
          "section": "Panel",
          "data": {
            "name": "expandable",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Expandable"
          }
        },
        {
          "name": "responsive",
          "section": "Panel",
          "data": {
            "name": "responsive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Responsive"
          }
        },
        {
          "name": "skrim",
          "section": "Panel",
          "data": {
            "name": "skrim",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Adds darker backdrop for modal panels"
          }
        },
        {
          "name": "tag",
          "section": "Panel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Panelbody",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "surfaceType",
          "section": "Panelcontent",
          "data": {
            "name": "surfaceType",
            "type": "\"alternate\"",
            "default": "",
            "required": "false",
            "description": "Type of Surface"
          }
        },
        {
          "name": "tag",
          "section": "Panelcontent",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Panelheader",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "Paneltoggle",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "Paneltoggle",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "colorScheme",
          "section": "Paneltoggle",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "Paneltoggle",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "Paneltoggle",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "Paneltoggle",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "Paneltoggle",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "Paneltoggle",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "Paneltoggle",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "Paneltoggle",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        }
      ]
    },
    {
      "name": "progress",
      "version": "0.0.1",
      "description": "This component is deprecated and will be removed in the next major version. Please use the ProgressCircular and ProgressLinear components.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Linear progress indicators",
          "description": "",
          "order": 1
        },
        {
          "name": "Circular progress indicators",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom progress indicators",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/indeterminate-progress",
            "github": "apps/workshop/src/examples/components/progress/indeterminate-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaMediaPauseAltTiny, VisaMediaPlayAltTiny } from '@visa/nova-icons-react';\nimport { Button, ProgressLabel, ProgressLinear, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'indeterminate-linear-progress';\n\nexport const IndeterminateProgress = () => {\n  const [paused, setPaused] = useState(false);\n  const [initiated, setInitiated] = useState(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n\nconst start = () => {\n  setInitiated(true);\n  setTimeout(() => {\n    setLoadingMsg('Loading...');\n  }, 0);\n}\n  \nconst reset = () => {\n  setInitiated(false);\n  setLoadingMsg('');\n}\n\n  return (\n    <Utility vFlexCol vGap={12}>\n        {initiated && (\n      <Utility vFlexGrow>\n        <UtilityFragment vMarginVertical={8}>\n          <ProgressLinear id={id} paused={paused} />\n        </UtilityFragment>\n        <ProgressLabel htmlFor={id}>\n          <Utility tag=\"span\" role=\"alert\">{loadingMsg}</Utility>\n        </ProgressLabel>\n      </Utility>\n        )}\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={() => start()}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => reset()}>\n          Reset\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => setPaused(!paused)}>\n          {paused ? (\n            <>\n              <VisaMediaPlayAltTiny />\n              Play\n            </>\n          ) : (\n            <>\n              <VisaMediaPauseAltTiny />\n              Pause\n            </>\n          )}\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Indeterminate linear progress indicator"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/indeterminate-no-label-progress",
            "github": "apps/workshop/src/examples/components/progress/indeterminate-no-label-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaMediaPauseAltTiny, VisaMediaPlayAltTiny } from '@visa/nova-icons-react';\nimport { Button, ProgressLinear, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'no-label-indeterminate-linear-progress';\n\nexport const IndeterminateNoLabelProgress = () => {\n  const [paused, setPaused] = useState(false);\n  const [initiated, setInitiated] = useState(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n\nconst start = () => {\n  setInitiated(true);\n  setTimeout(() => {\n    setLoadingMsg('Loading...');\n  }, 500);\n}\n  \nconst reset = () => {\n  setInitiated(false);\n  setLoadingMsg('');\n}\n\n  return (\n    <Utility vFlexCol vGap={12}>\n      {initiated && (\n      <Utility vFlexGrow>\n        <UtilityFragment vMarginVertical={8}>\n          <ProgressLinear aria-label=\"Please wait\" id={id} paused={paused} />\n        </UtilityFragment>\n        <label className=\"v-progress-label v-sr\" htmlFor={id}>\n          <Utility tag=\"span\" role=\"alert\">{loadingMsg}</Utility>\n        </label>\n      </Utility>\n      )}\n    <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={() => start()}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => reset()}>\n          Reset\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => setPaused(!paused)}>\n          {paused ? (\n            <>\n              <VisaMediaPlayAltTiny />\n              Play\n            </>\n          ) : (\n            <>\n              <VisaMediaPauseAltTiny />\n              Pause\n            </>\n          )}\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Indeterminate linear progress indicator without visible label"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/determinate-progress",
            "github": "apps/workshop/src/examples/components/progress/determinate-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Button, ProgressLabel, ProgressLinear, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useCallback, useState, useRef } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'determinate-linear-progress';\n\nexport const DeterminateProgress = () => {\n  const [value, setValue] = useState(0);\n  const [loadingMsg, setLoadingMsg] = useState('');\n  const countingRef = useRef(false);\n\n  const startCountUp = useCallback(async () => {\n    setValue(0);\n    countingRef.current = true;\n    setTimeout(() => setLoadingMsg('Loading...'), 500);\n    for (let i = 0; i < 100; i++) {\n      if (!countingRef.current) {\n        resetCount();\n        break;\n      }\n      await new Promise(resolve => setTimeout(resolve, 50)); // mock the time it takes to load\n      setValue(prev => prev + 1); // increment the value by 1 percent\n    }\n    setLoadingMsg('Loading complete');\n    countingRef.current = false;\n  }, []);\n  const resetCount = () => {\n    countingRef.current = false;\n    setValue(0);\n    setLoadingMsg('');\n  };\n  return (\n    <>\n      <UtilityFragment vMarginVertical={8}>\n        <ProgressLinear id={id} max={100} value={value}/>\n      </UtilityFragment>\n      <ProgressLabel htmlFor={id}>\n        <span>Filename.jpg</span>\n        <span>{value}%</span>\n        <span role=\"alert\" className='v-sr'>{loadingMsg}</span>\n      </ProgressLabel>\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={startCountUp}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={resetCount}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Determinate linear progress indicator"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/determinate-no-label-progress",
            "github": "apps/workshop/src/examples/components/progress/determinate-no-label-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Button, ProgressLabel, ProgressLinear, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useCallback, useState, useRef } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'no-label-determinate-linear-progress';\n\nexport const DeterminateNoLabelProgress = () => {\n  const [value, setValue] = useState(0);\n  const [loadingMsg, setLoadingMsg] = useState('');\n  const countingRef = useRef(false);\n\n  const startCountUp = useCallback(async () => {\n    setValue(0);\n    countingRef.current = true;\n    setTimeout(() => setLoadingMsg('Loading...'), 500);\n    for (let i = 0; i < 100; i++) {\n      if (!countingRef.current) {\n        resetCount();\n        break;\n      }\n      await new Promise(resolve => setTimeout(resolve, 50)); // mock the time it takes to load\n      setValue(prev => prev + 1); // increment the value by 1 percent\n    }\n    setLoadingMsg('Loading complete');\n    countingRef.current = false;\n  }, []);\n  const resetCount = () => {\n    countingRef.current = false;\n    setValue(0);\n    setLoadingMsg('');\n  };\n  return (\n    <>\n      <UtilityFragment vMarginVertical={8}>\n        <ProgressLinear id={id} max={100} value={value} />\n      </UtilityFragment>\n      <ProgressLabel htmlFor={id}>\n        <span>{value}%</span>\n        <span className=\"v-sr\" role=\"alert\">{loadingMsg}</span>\n      </ProgressLabel>\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={startCountUp}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={resetCount}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Determinate linear progress indicator without visible label"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/complete-progress",
            "github": "apps/workshop/src/examples/components/progress/complete-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaSuccessTiny } from '@visa/nova-icons-react';\nimport { ProgressLabel, ProgressLinear, Utility, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'complete-linear-progress';\n\nexport const CompleteProgress = () => {\n  return (\n    <>\n      <UtilityFragment vMarginVertical={8}>\n        <ProgressLinear completed id={id} max={100} value={100} aria-valuenow={100} />\n      </UtilityFragment>\n      <ProgressLabel htmlFor={id}>\n        <Utility tag=\"span\" vFlex vGap={4} role=\"alert\">\n          <VisaSuccessTiny />\n          File is now uploaded.\n        </Utility>\n        <span>100%</span>\n      </ProgressLabel>\n    </>\n  );\n};\n"
          },
          "name": "Completed linear progress indicator"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Linear progress indicators",
          "url": {
            "iframe": "components/progress/error-progress",
            "github": "apps/workshop/src/examples/components/progress/error-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { ProgressLinear, ProgressLabel, UtilityFragment, Utility } from '@visa/nova-react';\nimport { VisaErrorTiny } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-determinate-linear-progress';\n\nexport const ErrorProgress = () => {\n  return (\n    <>\n      <UtilityFragment vMarginVertical={8}>\n        <ProgressLinear id={id} invalid max={100} value={0} />\n      </UtilityFragment>\n      <ProgressLabel htmlFor={id}>\n        <Utility tag=\"span\" vFlex vGap={4} role=\"alert\">\n          <VisaErrorTiny />\n          This is required text that describes the error in more detail.\n        </Utility>\n        <span>0%</span>\n      </ProgressLabel>\n    </>\n  );\n};\n"
          },
          "name": "Error linear progress indicator"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/indeterminate-circular-small-progress",
            "github": "apps/workshop/src/examples/components/progress/indeterminate-circular-small-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaMediaPauseAltTiny, VisaMediaPlayAltTiny } from '@visa/nova-icons-react';\nimport { Button, ProgressCircular, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const IndeterminateCircularSmallProgress = () => {\n  const [paused, setPaused] = useState(false);\n  const [initiated, setInitiated] = useState(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n\nconst start = () => {\n  setInitiated(true);\n  setTimeout(() => {\n    setLoadingMsg('Loading...');\n  }, 0);\n}\n  \nconst reset = () => {\n  setInitiated(false);\n  setLoadingMsg('');\n}\n\n  return (\n    <Utility vFlexCol vGap={12}>\n      {initiated && (\n        <>\n          <ProgressCircular\n            className=\"v-flex-grow\"\n            indeterminate\n            paused={paused}\n            progressSize=\"small\"\n          />\n          <span className=\"v-sr\" role=\"alert\">{loadingMsg}</span>\n      </>\n      )}\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={() => start()}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => reset()}>\n          Reset\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => setPaused(!paused)}>\n          {paused ? (\n            <>\n              <VisaMediaPlayAltTiny />\n              Play\n            </>\n          ) : (\n            <>\n              <VisaMediaPauseAltTiny />\n              Pause\n            </>\n          )}\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Small indeterminate circular progress indicator"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/indeterminate-circular-progress",
            "github": "apps/workshop/src/examples/components/progress/indeterminate-circular-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaMediaPauseAltTiny, VisaMediaPlayAltTiny } from '@visa/nova-icons-react';\nimport { Button, ProgressCircular, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const IndeterminateCircularProgress = () => {\n  const [paused, setPaused] = useState(false);\n  const [initiated, setInitiated] = useState(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n\nconst start = () => {\n  setInitiated(true);\n  setTimeout(() => {\n    setLoadingMsg('Loading...');\n  }, 0);\n}\n  \nconst reset = () => {\n  setInitiated(false);\n  setLoadingMsg('');\n}\n\n  return (\n    <Utility vFlexCol vGap={12}>\n      {initiated && (\n      <ProgressCircular className=\"v-flex-grow\" indeterminate paused={paused}>\n        <span className=\"v-sr\" role=\"alert\">{loadingMsg}</span>\n      </ProgressCircular>\n      )}\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={() => start()}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => reset()}>\n          Reset\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={() => setPaused(!paused)}>\n          {paused ? (\n            <>\n              <VisaMediaPlayAltTiny />\n              Play\n            </>\n          ) : (\n            <>\n              <VisaMediaPauseAltTiny />\n              Pause\n            </>\n          )}\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Large indeterminate circular progress indicator"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/determinate-circular-small-progress",
            "github": "apps/workshop/src/examples/components/progress/determinate-circular-small-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Button, ProgressCircular, Typography, Utility } from '@visa/nova-react';\nimport { useCallback, useState, useRef } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'small-determinate-circular-progress';\n\nexport const DeterminateCircularSmallProgress = () => {\n  const [value, setValue] = useState(0);\n  const countingRef = useRef(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n  \n\n  const startCountUp = useCallback(async () => {\n    setValue(0);\n    countingRef.current = true;\n    setLoadingMsg('Loading...');\n    for (let i = 0; i < 100; i++) {\n      if (!countingRef.current) {\n        resetCount();\n        break;\n      }\n      await new Promise(resolve => setTimeout(resolve, 50)); // mock the time it takes to load\n      setValue(prev => prev + 1); // increment the value by 1 percent\n    }\n    setLoadingMsg('Loading complete');\n    countingRef.current = false;\n  }, []);\n  const resetCount = () => {\n    countingRef.current = false;\n    setValue(0);\n    setLoadingMsg('');\n  };\n  return (\n    <>\n      <ProgressCircular aria-labelledby={id} progressSize=\"small\" value={value} aria-valuenow={value}>\n        <Typography tag=\"div\" className=\"v-progress-label\" variant=\"body-2-bold\" id={id}>{value}%</Typography>\n      </ProgressCircular>\n      <Utility tag=\"span\" role=\"alert\" className=\"v-sr\">{loadingMsg}</Utility>\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={startCountUp}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={resetCount}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Small determinate circular progress indicator"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/determinate-circular-progress",
            "github": "apps/workshop/src/examples/components/progress/determinate-circular-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { Button, ProgressCircular, ProgressLabel, Typography, Utility } from '@visa/nova-react';\nimport { useCallback, useState, useRef } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'large-determinate-circular-progress';\n\nexport const DeterminateCircularProgress = () => {\n  const [value, setValue] = useState(0);\n  const countingRef = useRef(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n  const startCountUp = useCallback(async () => {\n    setValue(0);\n    countingRef.current = true;\n    setLoadingMsg('Loading...');\n    for (let i = 0; i < 100; i++) {\n      if (!countingRef.current) {\n        resetCount();\n        break;\n      }\n      await new Promise(resolve => setTimeout(resolve, 50)); // mock the time it takes to load\n      setValue(prev => prev + 1); // increment the value by 1 percent\n    }\n    setLoadingMsg('Loading complete');\n    countingRef.current = false;\n  }, []);\n  const resetCount = () => {\n    countingRef.current = false;\n    setValue(0);\n    setLoadingMsg('');\n  };\n  return (\n    <>\n      <ProgressCircular aria-labelledby={id} value={value} aria-valuenow={value}>\n        <ProgressLabel id={id}>\n          <Typography tag=\"div\" className=\"v-progress-label\" variant=\"body-2-bold\">{value}%</Typography>\n        </ProgressLabel>\n      </ProgressCircular>\n      <Utility tag=\"span\" role=\"alert\" className=\"v-sr\">{loadingMsg}</Utility>\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={startCountUp}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={resetCount}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Large determinate circular progress indicator"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/complete-circular-progress",
            "github": "apps/workshop/src/examples/components/progress/complete-circular-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { ProgressCircular, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'large-complete-circular-progress';\nconst value = 100;\n\nexport const CompleteCircularProgress = () => {\n  return (\n    <>\n      <ProgressCircular aria-labelledby={`${id} completed-circular-screen-reader-message`} value={value} aria-valuenow={value}>\n        <Typography id={id} tag=\"div\" className=\"v-progress-label\" variant=\"body-2-bold\">{value}%</Typography>\n      </ProgressCircular>\n      <Utility tag=\"span\" role=\"alert\" className=\"v-sr\" id=\"completed-circular-screen-reader-message\">Loading complete.</Utility>\n    </>\n  );\n};\n"
          },
          "name": "Completed determinate circular progress indicator"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Circular progress indicators",
          "url": {
            "iframe": "components/progress/error-circular-progress",
            "github": "apps/workshop/src/examples/components/progress/error-circular-progress.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { InputMessage } from '@visa/nova-react';\n\nexport const ErrorCircularProgress = () => {\n  return (\n    <InputMessage className='v-input-error' role=\"alert\">\n      <VisaErrorTiny />\n      This is required text that describes the error in more detail.\n    </InputMessage>\n  );\n};\n"
          },
          "name": "Error determinate circular progress indicator"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Custom progress indicators",
          "url": {
            "iframe": "components/progress/circular-custom-size-progress",
            "github": "apps/workshop/src/examples/components/progress/circular-custom-size-progress.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { Button, ProgressCircular, ProgressLabel, Typography, Utility } from '@visa/nova-react';\nimport { useCallback, useState, useRef } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'circular-custom-size-determinate-progress';\n\nexport const CircularCustomSizeProgress = () => {\n  const [value, setValue] = useState(0);\n  const countingRef = useRef(false);\n  const [loadingMsg, setLoadingMsg] = useState('');\n  const startCountUp = useCallback(async () => {\n    setValue(0);\n    countingRef.current = true;\n    setLoadingMsg('Loading...');\n    for (let i = 0; i < 100; i++) {\n      if (!countingRef.current) {\n        resetCount();\n        break;\n      }\n      await new Promise(resolve => setTimeout(resolve, 50)); // mock the time it takes to load\n      setValue(prev => prev + 1); // increment the value by 1 percent\n    }\n    setLoadingMsg('Loading complete');\n    countingRef.current = false;\n  }, []);\n  const resetCount = () => {\n    countingRef.current = false;\n    setValue(0);\n    setLoadingMsg('');\n  };\n  return (\n    <>\n      <ProgressCircular aria-labelledby={id} progressSize={100} value={value} aria-valuenow={value}>\n        <ProgressLabel id={id}>\n          <Typography tag=\"div\" className=\"v-progress-label\" variant=\"body-2-bold\">\n            {value}%\n          </Typography>\n        </ProgressLabel>\n      </ProgressCircular>\n      <Utility tag=\"span\" role=\"alert\" className=\"v-sr\">{loadingMsg}</Utility>\n      <Utility vMarginVertical={12} vFlex vGap={12}>\n        <Button onClick={startCountUp}>\n          Start\n        </Button>\n        <Button colorScheme=\"secondary\" onClick={resetCount}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Custom size determinate circular progress indicator"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Custom progress indicators",
          "url": {
            "iframe": "components/progress/reusable",
            "github": "apps/workshop/src/examples/components/progress/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny, VisaInformationTiny, VisaSuccessTiny, VisaWarningTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  type MessageType,\n  ProgressCircular,\n  ProgressLabel,\n  ProgressLinear,\n  ScreenReader,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport clsx from 'clsx';\nimport { type CSSProperties, useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\nconst ICON_MAP = {\n  error: <VisaErrorTiny />,\n  warning: <VisaWarningTiny />,\n  success: <VisaSuccessTiny />,\n  information: <VisaInformationTiny />,\n  subtle: undefined,\n};\n\nconst MAX = 100;\nconst MAX_CIRCULAR_PROGRESS_VISIBLE_SIZE = 48;\nconst MIN = 0;\n\nconst normalizeProgressValue = (value?: number | null): number | undefined => {\n  if (value === null || value === undefined) return undefined;\n  if (value < MIN) return MIN;\n  if (value > MAX) return MAX;\n  return Math.floor(value);\n};\n\n// Nova Progress Component Props\nexport type NovaProgressProps = {\n  completeStatusMessage?: string;\n  determinate?: boolean;\n  hideMessage?: boolean;\n  hideProgress?: boolean;\n  id?: string;\n  inline?: boolean;\n  loadingStatusMessage?: string;\n  message?: string;\n  messageType?: Exclude<MessageType, 'close'>;\n  paused?: boolean;\n  progress?: number;\n  size?: 'small' | 'large' | number;\n  speed?: number;\n  type?: 'linear' | 'circular';\n};\n\n// Main Nova Progress Component\nexport const NovaProgress = ({\n  completeStatusMessage = 'Loading complete',\n  determinate = false,\n  hideMessage = false,\n  hideProgress = false,\n  id: idProp,\n  inline = false,\n  loadingStatusMessage = 'Loading...',\n  message,\n  messageType = 'subtle',\n  paused: pausedProp = false,\n  progress: progressProp,\n  size,\n  speed,\n  type = 'circular',\n  ...remainingProps\n}: NovaProgressProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const circularProgressVisible =\n    determinate &&\n    !hideProgress &&\n    (size === undefined ||\n      typeof size === 'string' ||\n      (typeof size === 'number' && size >= MAX_CIRCULAR_PROGRESS_VISIBLE_SIZE));\n\n  const paused = determinate ? false : pausedProp || messageType === 'error';\n  // Normalize progress value\n  const progressValue = normalizeProgressValue(progressProp);\n\n  // Compute screen reader status message\n  const srStatusMessage = useMemo(() => {\n    if (!determinate || (progressValue || 0) < 100) return loadingStatusMessage;\n    return completeStatusMessage;\n  }, [determinate, progressValue, loadingStatusMessage, completeStatusMessage]);\n\n  // Get icon based on message type\n  const messageIcon = ICON_MAP[messageType];\n\n  if (type === 'linear')\n    return (\n      <>\n        <UtilityFragment vMarginVertical={8}>\n          <ProgressLinear\n            id={`${id}-progress`}\n            max={determinate ? MAX : undefined}\n            style={{ animationPlayState: paused ? 'paused' : undefined }}\n            value={determinate ? progressValue : undefined}\n            {...remainingProps}\n          />\n        </UtilityFragment>\n        <ProgressLabel htmlFor={`${id}-progress`}>\n          {message && (\n            <Utility className={hideMessage ? 'v-sr' : undefined} role=\"alert\" vFlex vGap={4}>\n              {messageIcon}\n              {message}\n            </Utility>\n          )}\n          {!hideProgress && determinate && <span>{progressValue}%</span>}\n\n          <ScreenReader tag=\"span\" role=\"alert\">\n            {srStatusMessage}\n          </ScreenReader>\n        </ProgressLabel>\n      </>\n    );\n\n  // Circular progress\n  return (\n    <Utility vFlex vFlexCol={inline ? false : true} vGap={8} vAlignItems={inline ? 'center' : undefined}>\n      <ProgressCircular\n        aria-invalid={messageType === 'error' ? 'true' : undefined}\n        aria-labelledby={`${id}-label ${id}-message`}\n        aria-valuenow={determinate ? progressValue : undefined}\n        indeterminate={!determinate}\n        progressSize={size}\n        style={\n          {\n            animationPlayState: paused ? 'paused' : 'running',\n            '--v-progress-animation-factor': speed ?? undefined,\n          } as CSSProperties\n        }\n        value={determinate ? progressValue : undefined}\n        {...remainingProps}\n      >\n        <ProgressLabel id={`${id}-label`}>\n          <ProgressLabel className={clsx(!circularProgressVisible && 'v-sr')} tag=\"div\" variant=\"body-2-bold\">\n            {determinate && `${progressValue}%`}\n            {!determinate && loadingStatusMessage}\n          </ProgressLabel>\n        </ProgressLabel>\n      </ProgressCircular>\n      <ProgressLabel>\n        <Utility\n          id={`${id}-message`}\n          tag=\"span\"\n          role=\"alert\"\n          className={clsx(hideMessage && 'v-sr', undefined)}\n          vFlex\n          vGap={4}\n        >\n          {messageIcon}\n          {message}\n        </Utility>\n      </ProgressLabel>\n    </Utility>\n  );\n};\n\n// export default NovaProgress;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  determinate: boolean;\n  hideMessage: boolean;\n  hideProgress: boolean;\n  inline: boolean;\n  message: string;\n  messageType: Exclude<MessageType, 'close'>;\n  paused: boolean;\n  progress: number;\n  size?: string;\n  speed?: number;\n  type: 'linear' | 'circular';\n}\n\n// Demo Component\nexport const NovaProgressDemo = () => {\n  const messageTypes: { label: string; value: Exclude<MessageType, 'close'> }[] = [\n    { label: 'Subtle', value: 'subtle' },\n    { label: 'Information', value: 'information' },\n    { label: 'Error', value: 'error' },\n    { label: 'Success', value: 'success' },\n    { label: 'Warning', value: 'warning' },\n  ];\n\n  const types: { label: string; value: 'linear' | 'circular' }[] = [\n    { label: 'Circular', value: 'circular' },\n    { label: 'Linear', value: 'linear' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    determinate: true,\n    hideMessage: false,\n    hideProgress: false,\n    inline: false,\n    message: 'Filename.jpg',\n    messageType: 'subtle',\n    paused: false,\n    progress: 70,\n    size: undefined,\n    speed: undefined,\n    type: 'linear',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value?: string | boolean | number) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  // Parse size value\n  const parsedSize = useMemo(() => {\n    const sizeValue = customizations.size;\n    if (!sizeValue) return undefined;\n    if (sizeValue === 'small' || sizeValue === 'large') return sizeValue;\n    const numValue = Number(sizeValue);\n    return isNaN(numValue) ? undefined : numValue;\n  }, [customizations.size]);\n\n  return (\n    <div>\n      <style>{`\n        .circular-progress-label {\n          block-size: 100%;\n          inline-size: 100%;\n      }\n      `}</style>\n\n      <NovaProgress\n        determinate={customizations.determinate}\n        hideMessage={customizations.hideMessage}\n        hideProgress={customizations.hideProgress}\n        inline={customizations.inline}\n        message={customizations.message || ''}\n        messageType={customizations.messageType}\n        paused={customizations.paused}\n        progress={customizations.progress}\n        size={parsedSize ?? undefined}\n        speed={customizations.speed}\n        type={customizations.type}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              {customizations.message && (\n                <NovaSelect\n                  label=\"Message type\"\n                  onChange={e => handleInputChange('messageType', e.target.value as DemoCustomizations['messageType'])}\n                  options={messageTypes}\n                  value={formValues.messageType}\n                />\n              )}\n\n              {customizations.determinate && (\n                <NovaInput\n                  clearable\n                  label=\"Progress\"\n                  onChange={e => handleInputChange('progress', e.target.value ? Number(e.target.value) : undefined)}\n                  type=\"number\"\n                  value={formValues.progress?.toString() || ''}\n                />\n              )}\n\n              {customizations.type === 'circular' && (\n                <>\n                  <NovaInput\n                    clearable\n                    label=\"Size\"\n                    message=\"Valid options are 'small', 'large', or a number.\"\n                    onChange={e => handleInputChange('size', e.target.value)}\n                    value={formValues.size || ''}\n                  />\n\n                  {!customizations.determinate && (\n                    <NovaInput\n                      clearable\n                      label=\"Speed\"\n                      message=\"The smaller the number the faster the animation.\"\n                      onChange={e => handleInputChange('speed', e.target.value ? Number(e.target.value) : undefined)}\n                      step={0.1}\n                      type=\"number\"\n                      value={formValues.speed?.toString() || ''}\n                    />\n                  )}\n                </>\n              )}\n\n              <NovaSelect\n                label=\"Type\"\n                onChange={e => handleInputChange('type', e.target.value as DemoCustomizations['type'])}\n                options={types}\n                value={formValues.type}\n              />\n\n              <NovaCheckbox\n                label=\"Determinate\"\n                checked={formValues.determinate}\n                onChange={e => handleInputChange('determinate', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Hide message\"\n                checked={formValues.hideMessage}\n                onChange={e => handleInputChange('hideMessage', e.target.checked)}\n              />\n\n              {customizations.type === 'circular' && !customizations.hideMessage && (\n                <NovaCheckbox\n                  label=\"Inline\"\n                  checked={formValues.inline}\n                  onChange={e => handleInputChange('inline', e.target.checked)}\n                />\n              )}\n\n              {!customizations.determinate && (\n                <NovaCheckbox\n                  label=\"Paused\"\n                  checked={formValues.paused}\n                  onChange={e => handleInputChange('paused', e.target.checked)}\n                />\n              )}\n\n              {customizations.determinate && (\n                <NovaCheckbox\n                  label=\"Hide progress\"\n                  checked={formValues.hideProgress}\n                  onChange={e => handleInputChange('hideProgress', e.target.checked)}\n                />\n              )}\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaProgressDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable progress indicator"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Progresscircular",
          "selector": "<ProgressCircular />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Circular indicator used to show the progress of a task or process."
        },
        {
          "order": 2,
          "name": "Progresslabel",
          "selector": "<ProgressLabel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Label used with a progress component for textual representation of status."
        },
        {
          "order": 3,
          "name": "Progresslinear",
          "selector": "<ProgressLinear />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Linear indicator used to show the progress of a task or process."
        }
      ],
      "properties": [
        {
          "name": "indeterminate",
          "section": "Progresscircular",
          "data": {
            "name": "indeterminate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "If the Progress is Indeterminate Progress"
          }
        },
        {
          "name": "paused",
          "section": "Progresscircular",
          "data": {
            "name": "paused",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Is Paused"
          }
        },
        {
          "name": "progressSize",
          "section": "Progresscircular",
          "data": {
            "name": "progressSize",
            "type": "number , \"small\" , \"large\"",
            "default": "large",
            "required": "false",
            "description": "Width of the Circular Progress"
          }
        },
        {
          "name": "value",
          "section": "Progresscircular",
          "data": {
            "name": "value",
            "type": "number",
            "default": "",
            "required": "false",
            "description": "Percent Complete"
          }
        },
        {
          "name": "colorScheme",
          "section": "Progresslabel",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Progresslabel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "label",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Progresslabel",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        },
        {
          "name": "completed",
          "section": "Progresslinear",
          "data": {
            "name": "completed",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Is Completed"
          }
        },
        {
          "name": "invalid",
          "section": "Progresslinear",
          "data": {
            "name": "invalid",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Is Error State"
          }
        },
        {
          "name": "paused",
          "section": "Progresslinear",
          "data": {
            "name": "paused",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Is Paused"
          }
        },
        {
          "name": "tag",
          "section": "Progresslinear",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "progress",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "radio",
      "version": "0.0.1",
      "description": "Interactive elements that allow users to select a single option from a list.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default radio buttons",
          "description": "",
          "order": 1
        },
        {
          "name": "Radio button groups",
          "description": "",
          "order": 2
        },
        {
          "name": "Radio button panels",
          "description": "",
          "order": 3
        },
        {
          "name": "Radio button panel groups",
          "description": "",
          "order": 4
        },
        {
          "name": "Custom radios",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/with-label-radio",
            "github": "apps/workshop/src/examples/components/radio/with-label-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-radio';\n\nexport const DefaultRadio = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Radio id={id} name={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Radio button with label"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/without-visible-label-radio",
            "github": "apps/workshop/src/examples/components/radio/without-visible-label-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'no-label-radio';\n\nexport const NoLabelRadio = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Radio id={id} aria-label=\"Label\" name={id} />\n    </Utility>\n  );\n};\n"
          },
          "name": "Radio button without visible label"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/with-description-radio",
            "github": "apps/workshop/src/examples/components/radio/with-description-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Label, Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'with-description-radio';\n\nexport const WithDescriptionRadio = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <Utility vFlex vGap={2}>\n        <Radio id={id} name={id} />\n        <Utility vFlex vFlexCol vGap={2} vMarginVertical={10}>\n          <Label htmlFor={id}>Label</Label>\n          <InputMessage id={`${id}-message`}>\n            This is optional text that describes the label in more detail.\n          </InputMessage>\n        </Utility>\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Radio button with description"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/selected-radio",
            "github": "apps/workshop/src/examples/components/radio/selected-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'selected-radio';\n\nexport const SelectedRadio = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Radio defaultChecked id={id} name={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Selected radio button"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/error-radio",
            "github": "apps/workshop/src/examples/components/radio/error-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useRef, useState, type ChangeEvent } from 'react';\nimport { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputMessage, Label, Radio, Utility, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'radio-error';\n\nexport const ErrorRadio = () => {\n  const radioRef = useRef<HTMLInputElement>(null);\n  const [checked, setChecked] = useState(false);\n  const [invalid, setInvalid] = useState(false);\n\n  const onRadioButtonChange = (event: ChangeEvent<HTMLInputElement>) => {\n    setChecked(event.target.checked);\n  };\n\n  const onSubmit = () => {\n    if (checked) setInvalid(false);\n    else {\n      setInvalid(true);\n      radioRef.current?.focus();\n    }\n  };\n  return (\n    <>\n      <fieldset aria-labelledby={`${id}-message`}>\n        <Utility vFlex vAlignItems=\"center\" vGap={2}>\n          <Radio\n            aria-invalid={invalid}\n            aria-required=\"true\"\n            checked={checked}\n            id={id}\n            name={id}\n            onChange={onRadioButtonChange}\n            ref={radioRef}\n          />\n          <Label htmlFor={id} id={`${id}-label`}>\n            Label\n          </Label>\n        </Utility>\n        {invalid && (\n          <UtilityFragment vAlignItems=\"center\" vFlex vGap={2} vMarginTop={4}>\n            <InputMessage\n              aria-atomic=\"true\"\n              aria-live=\"assertive\"\n              className=\"v-typography-label\"\n              id={`${id}-message`}\n              role=\"alert\"\n            >\n              <VisaErrorTiny />\n              This is required text that describes the error in more detail.\n            </InputMessage>\n          </UtilityFragment>\n        )}\n      </fieldset>\n      <Utility vFlex vGap={12} vMarginTop={12}>\n        <Button onClick={onSubmit}>Submit</Button>\n        <Button colorScheme=\"secondary\" onClick={() => setChecked(false)}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Radio button with error"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/disabled-radio",
            "github": "apps/workshop/src/examples/components/radio/disabled-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'radio-disabled';\n\nexport const DisabledRadio = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Radio disabled id={id} name={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled radio button"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default radio buttons",
          "url": {
            "iframe": "components/radio/disabled-selected-radio",
            "github": "apps/workshop/src/examples/components/radio/disabled-selected-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'radio-disabled-selected';\n\nexport const DisabledSelectedRadio = () => {\n  return (\n    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n      <Radio defaultChecked disabled id={id} name={id} />\n      <Label htmlFor={id}>Label</Label>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled and selected radio button"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button groups",
          "url": {
            "iframe": "components/radio/group-radio",
            "github": "apps/workshop/src/examples/components/radio/group-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'group-radio';\n\nconst radios = ['Label 1', 'Label 2', 'Label 3'];\n\nexport const GroupRadio = () => {\n  return (\n    <fieldset>\n      <Typography tag=\"legend\" variant=\"label\">\n        Group label (required)\n      </Typography>\n      <Utility vFlex vFlexCol vGap={4}>\n        {radios.map((radio, index) => (\n          <Utility key={`${id}-option-${index}`} vAlignItems=\"center\" vFlex vGap={2}>\n            <Radio id={`${id}-option-${index}`} name={`${id}-options`} />\n            <Label htmlFor={`${id}-option-${index}`}>{radio}</Label>\n          </Utility>\n        ))}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Radio button group"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button groups",
          "url": {
            "iframe": "components/radio/error-group-radio",
            "github": "apps/workshop/src/examples/components/radio/error-group-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useRef, useState, type ChangeEvent } from 'react';\nimport { Button, InputMessage, Label, Radio, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-group-radio';\n\nconst radios = ['Label 1', 'Label 2', 'Label 3'];\n\nexport const ErrorGroupRadio = () => {\n  const ref = useRef<HTMLInputElement>(null);\n  const [errorState, setErrorState] = useState(false);\n  const [option, setOption] = useState('');\n\n  const handleChangeState = (e: ChangeEvent<HTMLInputElement>) => {\n    setOption(e.target.value);\n  };\n  const handleOnSubmit = () => {\n    if (option !== '') {\n      setErrorState(false);\n    } else {\n      setOption('');\n      setErrorState(true);\n    }\n    ref?.current?.focus();\n  };\n\n  return (\n    <>\n      <fieldset aria-invalid={errorState} aria-labelledby={`${id}-legend ${id}-message`}>\n        <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n          Group label (required)\n        </Typography>\n        <Utility vFlex vFlexCol vGap={4}>\n          {radios.map((radio, index) => (\n            <Utility key={`${id}-option-${index}`} vAlignItems=\"center\" vFlex vGap={2}>\n              <Radio\n                aria-invalid={errorState}\n                checked={option === index.toString()}\n                id={`${id}-option-${index}`}\n                name={`${id}-options`}\n                onChange={handleChangeState}\n                ref={index === 0 ? ref : undefined}\n                value={index}\n              />\n              <Label htmlFor={`${id}-option-${index}`}>{radio}</Label>\n            </Utility>\n          ))}\n        </Utility>\n        {errorState && (\n          <InputMessage\n            aria-atomic=\"true\"\n            aria-live=\"assertive\"\n            className=\"v-typography-label v-flex v-align-items-center\"\n            id={`${id}-message`}\n            role=\"alert\"\n          >\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </fieldset>\n      <Utility vFlex vFlexRow vPaddingTop={4} vGap={12}>\n        <Button onClick={handleOnSubmit}>Submit</Button>\n        <Button colorScheme=\"secondary\" onClick={() => setOption('')}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Radio button group with error"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button groups",
          "url": {
            "iframe": "components/radio/horizontal-group-radio",
            "github": "apps/workshop/src/examples/components/radio/horizontal-group-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Radio, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'horizontal-group-radio';\n\nconst radios = ['Label 1', 'Label 2', 'Label 3'];\n\nexport const HorizontalGroupRadio = () => {\n  return (\n    <fieldset>\n      <Typography tag=\"legend\" variant=\"label\">\n        Group label (required)\n      </Typography>\n      <Utility vFlex vFlexRow vGap={24} vFlexWrap>\n        {radios.map((radio, index) => (\n          <Utility key={`${id}-option-${index}`} vFlex vAlignItems=\"center\" vGap={2}>\n            <Radio id={`${id}-option-${index}`} name={`${id}-options`} />\n            <Label htmlFor={`${id}-option-${index}`}>{radio}</Label>\n          </Utility>\n        ))}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Horizontal radio button group"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button panels",
          "url": {
            "iframe": "components/radio/with-description-panel-radio",
            "github": "apps/workshop/src/examples/components/radio/with-description-panel-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Radio, RadioPanel, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'with-description-panel-radio';\n\nexport const WithDescriptionPanelRadio = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <RadioPanel className=\"v-align-items-start\" htmlFor={id}>\n        <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n          <Radio className=\"v-flex-shrink-0\" id={id} name={id} />\n          <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n            Label\n            <InputMessage id={`${id}-message`}>\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          </Utility>\n        </Utility>\n      </RadioPanel>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Radio button panel"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button panels",
          "url": {
            "iframe": "components/radio/without-description-panel-radio",
            "github": "apps/workshop/src/examples/components/radio/without-description-panel-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Radio, RadioPanel, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'with-description-panel-radio';\n\nexport const WithoutDescriptionPanelRadio = () => {\n  return (\n    <RadioPanel className=\"v-align-items-start\" htmlFor={id}>\n      <Utility vAlignItems=\"center\" vFlex vGap={2} style={{ inlineSize: '100%' }}>\n        <Radio className=\"v-flex-shrink-0\" id={id} name={id} />\n        Label\n      </Utility>\n    </RadioPanel>\n  );\n};\n"
          },
          "name": "Radio button panel without description"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button panels",
          "url": {
            "iframe": "components/radio/disabled-panel-radio",
            "github": "apps/workshop/src/examples/components/radio/disabled-panel-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Radio, RadioPanel, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'radio-panel-disabled';\n\nexport const DisabledPanelRadio = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-message`}>\n      <RadioPanel className=\"v-align-items-start\" htmlFor={id}>\n        <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n          <Radio className=\"v-flex-shrink-0\" disabled id={id} name=\"radio-13\" />\n          <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n            Label\n            <InputMessage id={`${id}-message`}>\n              This is optional text that describes the label in more detail.\n            </InputMessage>\n          </Utility>\n        </Utility>\n      </RadioPanel>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Disabled radio button panel"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button panel groups",
          "url": {
            "iframe": "components/radio/group-panel-radio",
            "github": "apps/workshop/src/examples/components/radio/group-panel-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Radio, RadioPanel, Typography, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'group-panel-radio';\n\nconst radios = ['Label 1', 'Label 2', 'Label 3'];\n\nexport const GroupPanelRadio = () => {\n  return (\n    <fieldset aria-labelledby={`${id}-legend`}>\n      <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n        Group label (required)\n      </Typography>\n      <Utility vFlex vFlexCol vGap={8}>\n        {radios.map((radio, index) => (\n          <RadioPanel className=\"v-align-items-start\" htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`}>\n            <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n              <Radio className=\"v-flex-shrink-0\" id={`${id}-option-${index}`} name={`${id}-options`} />\n              <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n                {radio}\n                <InputMessage id={`${id}-radio-${index}-message`}>\n                  This is optional text that describes the label in more detail.\n                </InputMessage>\n              </Utility>\n            </Utility>\n          </RadioPanel>\n        ))}\n      </Utility>\n    </fieldset>\n  );\n};\n"
          },
          "name": "Radio button panel group"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Radio button panel groups",
          "url": {
            "iframe": "components/radio/error-group-panel-radio",
            "github": "apps/workshop/src/examples/components/radio/error-group-panel-radio.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Utility, RadioPanel, Radio, Label, InputMessage, Button, Typography } from '@visa/nova-react';\nimport { useRef, useState, type ChangeEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-group-panel-radio';\n\nconst radios = ['Label 1', 'Label 2', 'Label 3'];\n\nexport const ErrorPanelGroupRadio = () => {\n  const ref = useRef<HTMLInputElement>(null);\n  const [errorState, setErrorState] = useState(false);\n  const [option, setOption] = useState('');\n\n  const handleChangeState = (e: ChangeEvent<HTMLInputElement>) => {\n    setOption(e.target.value);\n  };\n  const handleOnSubmit = () => {\n    if (option !== '') {\n      setErrorState(false);\n    } else {\n      setOption('');\n      setErrorState(true);\n    }\n    ref?.current?.focus();\n  };\n  return (\n    <>\n      <fieldset aria-labelledby={`${id}-legend ${id}-message`}>\n        <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n          Group label (required)\n        </Typography>\n        <Utility vFlex vFlexCol vGap={8}>\n          {radios.map((radio, index) => (\n            <RadioPanel className=\"v-align-items-start\" htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`}>\n              <Utility vFlex vGap={2} style={{ inlineSize: '100%' }}>\n                <Radio\n                  aria-describedby={`${id}-option-${index}-message`}\n                  aria-invalid={errorState}\n                  checked={option === `${index}`}\n                  className=\"v-flex-shrink-0\"\n                  id={`${id}-option-${index}`}\n                  name={`${id}-options`}\n                  onChange={handleChangeState}\n                  ref={index === 0 ? ref : undefined}\n                  value={index}\n                />\n                <Utility vFlex vFlexCol vGap={2} vMarginVertical={8}>\n                  <Label htmlFor={`${id}-option-${index}`}>{radio}</Label>\n                  <InputMessage id={`${id}-option-${index}-message`}>\n                    This is optional text that describes the label in more detail.\n                  </InputMessage>\n                </Utility>\n              </Utility>\n            </RadioPanel>\n          ))}\n        </Utility>\n        {errorState && (\n          <InputMessage\n            aria-atomic=\"true\"\n            aria-live=\"assertive\"\n            className=\"v-typography-label v-flex v-align-items-center\"\n            id={`${id}-message`}\n            role=\"alert\"\n          >\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail.\n          </InputMessage>\n        )}\n      </fieldset>\n      <Utility vFlex vFlexRow vPaddingTop={12} vGap={12}>\n        <Button onClick={handleOnSubmit}>Submit</Button>\n        <Button colorScheme=\"secondary\" onClick={() => setOption('')}>\n          Reset\n        </Button>\n      </Utility>\n    </>\n  );\n};\n"
          },
          "name": "Radio button panel group with error"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Custom radios",
          "url": {
            "iframe": "components/radio/reusable",
            "github": "apps/workshop/src/examples/components/radio/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  InputContainer,\n  InputMessage,\n  Label,\n  Radio,\n  RadioPanel,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport type { RadioProperties } from '@visa/nova-react';\nimport { useId, useMemo, useRef, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Nova Radio Component Props\nexport type NovaRadioProps = RadioProperties & {\n  alignEnd?: boolean;\n  checked?: boolean;\n  description?: string;\n  disabled?: boolean;\n  id?: string;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  name: string;\n  panel?: boolean;\n  required?: boolean;\n  value: string | number;\n};\n\n// Main Nova Radio Component\nexport const NovaRadio = ({\n  alignEnd = false,\n  checked = false,\n  description,\n  disabled = false,\n  id: idProp,\n  invalid = false,\n  label = '',\n  message,\n  name,\n  onChange,\n  panel = false,\n  required = false,\n  value,\n  ...remainingInputProps\n}: NovaRadioProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n  const radioInputRef = useRef<HTMLInputElement>(null);\n\n  // Calculate aria-describedby\n  const inputDescribedBy = useMemo(() => {\n    const ids: string[] = [];\n    if (message) ids.push(`${id}-message`);\n    if (description) ids.push(`${id}-description`);\n    return ids.length > 0 ? ids.join(' ') : undefined;\n  }, [message, description, id]);\n\n  // Handle click on panel\n  const handlePanelClick = () => {\n    if (!disabled && radioInputRef.current) {\n      radioInputRef.current.click();\n    }\n  };\n\n  const radioContent = (\n    <UtilityFragment vAlignItems={panel && description ? 'start' : undefined} vFlex vFlexRowReverse={alignEnd}>\n      <InputContainer>\n        <Radio\n          ref={radioInputRef}\n          aria-describedby={inputDescribedBy}\n          aria-required={required ? true : undefined}\n          checked={checked}\n          disabled={disabled}\n          id={`${id}-input`}\n          aria-invalid={invalid}\n          name={name}\n          onChange={onChange}\n          required={required}\n          type=\"radio\"\n          value={value}\n          {...remainingInputProps}\n        />\n        <Utility vFlex vFlexCol vFlexGrow={alignEnd} vGap={2} vMarginVertical={8}>\n          <Label htmlFor={`${id}-input`}>{label}</Label>\n          {description && <InputMessage id={`${id}-description`}>{description}</InputMessage>}\n        </Utility>\n      </InputContainer>\n    </UtilityFragment>\n  );\n\n  return (\n    <>\n      {panel ? <RadioPanel onClick={handlePanelClick}>{radioContent}</RadioPanel> : radioContent}\n\n      <UtilityFragment vMarginTop={4}>\n        <InputMessage\n          aria-atomic={invalid ? true : undefined}\n          aria-live={invalid ? 'assertive' : undefined}\n          id={`${id}-message`}\n        >\n          {invalid && message && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </UtilityFragment>\n    </>\n  );\n};\n\n// export default NovaRadio;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  alignEnd: boolean;\n  description: string;\n  disabled: boolean;\n  errorMessage: string;\n  invalid: boolean;\n  label: string;\n  panel: boolean;\n  required: boolean;\n}\n\n// Demo Component\nexport const NovaRadioDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    alignEnd: false,\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    invalid: false,\n    label: 'Label',\n    panel: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <NovaRadio\n        alignEnd={customizations.alignEnd}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : undefined}\n        name=\"radio-demo\"\n        panel={customizations.panel}\n        required={customizations.required}\n        value=\"radio-value\"\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <NovaCheckbox\n                label=\"Align end\"\n                checked={formValues.alignEnd}\n                onChange={e => handleInputChange('alignEnd', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Panel\"\n                checked={formValues.panel}\n                onChange={e => handleInputChange('panel', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaRadioDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable radio button"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Custom radios",
          "url": {
            "iframe": "components/radio/reusable-group",
            "github": "apps/workshop/src/examples/components/radio/reusable-group.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, Checkbox, InputMessage, Label, Textarea, Typography, Utility } from '@visa/nova-react';\nimport { useId, useMemo, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaInput } from '../input/reusable';\n// This is from the reusable radio component example. If copying this code please copy the component into your codebase.\nimport { NovaRadio } from './reusable';\n\n// Radio Type\nexport interface Radio {\n  description?: string;\n  disabled?: boolean;\n  label: string;\n  panel?: boolean;\n  value: string | number;\n}\n\n// Nova Radio Group Component Props\nexport interface NovaRadioGroupProps {\n  alignEnd?: boolean;\n  description?: string;\n  disabled?: boolean;\n  id?: string;\n  inline?: boolean;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  name?: string;\n  onChange?: (value: string | number) => void;\n  panel?: boolean;\n  radios?: Radio[];\n  required?: boolean;\n  value?: string | number;\n}\n\n// Main Nova Radio Group Component\nexport const NovaRadioGroup = ({\n  alignEnd = false,\n  description,\n  disabled = false,\n  id: idProp,\n  inline = true,\n  invalid = false,\n  label = '',\n  message,\n  name: nameProp,\n  onChange,\n  panel = false,\n  radios = [],\n  required = false,\n  value,\n}: NovaRadioGroupProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n  const name = nameProp ?? `${id}-radio`;\n\n  // Calculate aria-labelledby for fieldset\n  const fieldsetLabelledBy = useMemo(() => {\n    const ids: string[] = [`${id}-legend`];\n    if (description) ids.push(`${id}-description`);\n    return ids.join(' ');\n  }, [description, id]);\n\n  return (\n    <fieldset aria-labelledby={fieldsetLabelledBy}>\n      <Typography id={`${id}-legend`} tag=\"legend\" variant=\"label\">\n        {label}\n        {required ? ' (required)' : ''}\n      </Typography>\n\n      {description && <InputMessage id={`${id}-description`}>{description}</InputMessage>}\n\n      <div role=\"radiogroup\" aria-required={required ? true : undefined}>\n        <Utility vFlex vFlexCol={!inline} vGap={inline ? 24 : undefined}>\n          {radios.map((radio, i) => (\n            <NovaRadio\n              key={`${id}-radio-${i}`}\n              alignEnd={alignEnd}\n              description={radio.description}\n              disabled={disabled || radio.disabled}\n              invalid={invalid}\n              label={radio.label}\n              name={name}\n              onChange={e => onChange?.(e.target.value)}\n              panel={panel || radio.panel}\n              value={radio.value}\n              checked={value === radio.value}\n            />\n          ))}\n        </Utility>\n      </div>\n\n      <InputMessage\n        aria-atomic={invalid ? true : undefined}\n        aria-live={invalid ? 'assertive' : undefined}\n        id={`${id}-message`}\n      >\n        {invalid && <VisaErrorTiny />}\n        {message && message}\n      </InputMessage>\n    </fieldset>\n  );\n};\n\n// export default NovaRadioGroup;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  alignEnd: boolean;\n  description: string;\n  disabled: boolean;\n  errorMessage: string;\n  inline: boolean;\n  invalid: boolean;\n  label: string;\n  panel: boolean;\n  radios: string;\n  required: boolean;\n}\n\n// Demo Component\nexport const NovaRadioGroupDemo = () => {\n  const radios: Radio[] = [\n    {\n      label: 'Label 1',\n      value: 'value-1',\n    },\n    {\n      label: 'Label 2',\n      value: 'value-2',\n    },\n    {\n      label: 'Label 3',\n      value: 'value-3',\n    },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    alignEnd: false,\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    inline: false,\n    invalid: false,\n    label: 'Group label',\n    panel: false,\n    radios: JSON.stringify(radios, null, 4),\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<Omit<DemoCustomizations, 'radios'> & { radios: Radio[] }>({\n    ...defaultCustomizations,\n    radios,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedRadios = JSON.parse(formValues.radios || '[]') as Radio[];\n      setCustomizations({\n        ...formValues,\n        radios: parsedRadios,\n      });\n    } catch (error) {\n      console.error('Invalid JSON for radios:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      radios,\n    });\n  };\n\n  return (\n    <div>\n      <NovaRadioGroup\n        alignEnd={customizations.alignEnd}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        inline={customizations.inline}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : undefined}\n        panel={customizations.panel}\n        radios={customizations.radios}\n        required={customizations.required}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <div>\n                <Label htmlFor=\"radios-input\">Radios</Label>\n                <Textarea\n                  fixed={false}\n                  id=\"radios-input\"\n                  onChange={e => handleInputChange('radios', e.target.value)}\n                  style={{ blockSize: '100px' }}\n                  value={formValues.radios}\n                />\n              </div>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.alignEnd}\n                  onChange={e => handleInputChange('alignEnd', e.target.checked)}\n                />\n                Align end\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.disabled}\n                  onChange={e => handleInputChange('disabled', e.target.checked)}\n                />\n                Disabled\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.inline} onChange={e => handleInputChange('inline', e.target.checked)} />\n                Inline\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.invalid} onChange={e => handleInputChange('invalid', e.target.checked)} />\n                Invalid\n              </Label>\n\n              <Label>\n                <Checkbox checked={formValues.panel} onChange={e => handleInputChange('panel', e.target.checked)} />\n                Panel\n              </Label>\n\n              <Label>\n                <Checkbox\n                  checked={formValues.required}\n                  onChange={e => handleInputChange('required', e.target.checked)}\n                />\n                Required\n              </Label>\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaRadioGroupDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable radio button group"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Radio",
          "selector": "<Radio />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive elements that allow users to select a single option from a list."
        },
        {
          "order": 2,
          "name": "Radiopanel",
          "selector": "<RadioPanel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container used with a radio component to add a border and background color."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Radio",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "input",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "colorScheme",
          "section": "Radiopanel",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Radiopanel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Radiopanel",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "section-message",
      "version": "0.0.1",
      "description": "Section-level messages providing information about the status of a page or action.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Informational section messages",
          "description": "",
          "order": 1
        },
        {
          "name": "Success section messages",
          "description": "",
          "order": 2
        },
        {
          "name": "Warning section messages",
          "description": "",
          "order": 3
        },
        {
          "name": "Error section messages headline",
          "description": "",
          "order": 4
        },
        {
          "name": "Subtle section messages headline",
          "description": "",
          "order": 5
        },
        {
          "name": "Custom section messages",
          "description": "",
          "order": 6
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/empty-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/empty-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { SectionMessage } from '@visa/nova-react';\n\nexport const EmptyInformationSectionMessage = () => {\n  return <SectionMessage />;\n};\n"
          },
          "name": "Empty informational section message"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/default-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/default-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultInformationSectionMessage = () => {\n  return (\n    <SectionMessage>\n      <MessageIcon />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Default informational section message"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/title-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/title-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const TitleInformationSectionMessage = () => {\n  return (\n    <SectionMessage>\n      <MessageIcon />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography tag=\"h4\" variant=\"body-2-bold\">\n            Informational title\n          </Typography>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Informational section message with title"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/link-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/link-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Link, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const LinkInformationSectionMessage = () => {\n  return (\n    <SectionMessage>\n      <MessageIcon />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Link href=\"./section-message\">Destination label</Link>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Informational section message with link"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/button-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/button-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const ButtonInformationSectionMessage = () => {\n  return (\n    <SectionMessage>\n      <MessageIcon />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Informational section message with button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Informational section messages",
          "url": {
            "iframe": "components/section-message/persistent-information-section-message",
            "github": "apps/workshop/src/examples/components/section-message/persistent-information-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { SectionMessage, SectionMessageContent, Typography, UtilityFragment } from '@visa/nova-react';\n\nexport const PersistentInformationSectionMessage = () => {\n  return (\n    <SectionMessage>\n      <MessageIcon />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Informational section message without close icon button"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/empty-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/empty-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { SectionMessage } from '@visa/nova-react';\n\nexport const EmptySuccessSectionMessage = () => {\n  return <SectionMessage messageType=\"success\" />;\n};\n"
          },
          "name": "Empty success section message"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/default-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/default-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultSuccessSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Default success section message"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/title-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/title-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const TitleSuccessSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography tag=\"h4\" variant=\"body-2-bold\">\n            Success title\n          </Typography>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Success section message with title"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/link-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/link-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Link, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const LinkSuccessSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Link href=\"./section-message\">Destination label</Link>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Success section message with link"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/button-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/button-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const ButtonSuccessSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Success section message with button"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Success section messages",
          "url": {
            "iframe": "components/section-message/persistent-success-section-message",
            "github": "apps/workshop/src/examples/components/section-message/persistent-success-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { SectionMessage, SectionMessageContent, Typography, UtilityFragment } from '@visa/nova-react';\n\nexport const PersistentSuccessSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"success\">\n      <MessageIcon messageType=\"success\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Success section message without close icon button"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/empty-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/empty-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { SectionMessage } from '@visa/nova-react';\n\nexport const EmptyWarningSectionMessage = () => {\n  return <SectionMessage messageType=\"warning\" />;\n};\n"
          },
          "name": "Empty warning section message"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/default-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/default-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultWarningSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Default warning section message"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/title-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/title-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const TitleWarningSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography tag=\"h4\" variant=\"body-2-bold\">\n            Warning title\n          </Typography>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Warning section message with title"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/link-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/link-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Link, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const LinkWarningSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Link href=\"./section-message\">Destination label</Link>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Warning section message with link"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/button-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/button-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const ButtonWarningSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Warning section message with button"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Warning section messages",
          "url": {
            "iframe": "components/section-message/persistent-warning-section-message",
            "github": "apps/workshop/src/examples/components/section-message/persistent-warning-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { SectionMessage, SectionMessageContent, Typography, UtilityFragment } from '@visa/nova-react';\n\nexport const PersistentWarningSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"warning\">\n      <MessageIcon messageType=\"warning\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Warning section message without close icon button"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/empty-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/empty-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { SectionMessage } from '@visa/nova-react';\n\nexport const EmptyErrorSectionMessage = () => {\n  return <SectionMessage messageType=\"error\" />;\n};\n"
          },
          "name": "Empty error section message"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/default-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/default-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultErrorSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Default error section message"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/title-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/title-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const TitleErrorSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography tag=\"h4\" variant=\"body-2-bold\">\n            Error title\n          </Typography>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Error section message with title"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/link-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/link-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Link, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const LinkErrorSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Link href=\"./section-message\">Destination label</Link>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Error section message with link"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/button-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/button-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const ButtonErrorSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Error section message with button"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Error section messages headline",
          "url": {
            "iframe": "components/section-message/persistent-error-section-message",
            "github": "apps/workshop/src/examples/components/section-message/persistent-error-section-message.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { SectionMessage, SectionMessageContent, Typography, UtilityFragment } from '@visa/nova-react';\n\nexport const PersistentErrorSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"error\">\n      <MessageIcon messageType=\"error\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Error section message without close icon button"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/empty-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/empty-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { SectionMessage } from '@visa/nova-react';\n\nexport const EmptySubtleSectionMessage = () => {\n  return <SectionMessage messageType=\"subtle\" />;\n};\n"
          },
          "name": "Empty subtle section message"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/default-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/default-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const DefaultSubtleSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"subtle\">\n      <MessageIcon messageType=\"subtle\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Default subtle section message"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/title-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/title-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  UtilityFragment,\n} from '@visa/nova-react';\n\nexport const TitleSubtleSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"subtle\">\n      <MessageIcon messageType=\"subtle\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography tag=\"h4\" variant=\"body-2-bold\">\n            Error title\n          </Typography>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Subtle section message with title"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/link-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/link-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Link, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const LinkSubtleSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"subtle\">\n      <MessageIcon messageType=\"subtle\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Link href=\"./section-message\">Destination label</Link>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Subtle section message with link"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/button-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/button-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport { Button, SectionMessage, SectionMessageCloseButton, SectionMessageContent, Typography } from '@visa/nova-react';\n\nexport const ButtonSubtleSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"subtle\">\n      <MessageIcon messageType=\"subtle\" />\n      <SectionMessageContent>\n        <Typography className=\"v-mb-8\">\n          This is required text that describes the section message in more detail.\n        </Typography>\n        <Button colorScheme=\"secondary\">Primary action</Button>\n      </SectionMessageContent>\n      <SectionMessageCloseButton>\n        <VisaCloseTiny />\n      </SectionMessageCloseButton>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Subtle section message with button"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Subtle section messages headline",
          "url": {
            "iframe": "components/section-message/persistent-subtle-section-message",
            "github": "apps/workshop/src/examples/components/section-message/persistent-subtle-section-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { MessageIcon } from '@visa/nova-icons-react';\nimport { SectionMessage, SectionMessageContent, Typography, UtilityFragment } from '@visa/nova-react';\n\nexport const PersistentSubtleSectionMessage = () => {\n  return (\n    <SectionMessage messageType=\"subtle\">\n      <MessageIcon messageType=\"subtle\" />\n      <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n        <SectionMessageContent>\n          <Typography>This is required text that describes the section message in more detail.</Typography>\n        </SectionMessageContent>\n      </UtilityFragment>\n    </SectionMessage>\n  );\n};\n"
          },
          "name": "Subtle section message without close icon button"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Custom section messages",
          "url": {
            "iframe": "components/section-message/reusable",
            "github": "apps/workshop/src/examples/components/section-message/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { MessageIcon, VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Link,\n  type MessageType,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  type SectionMessageProperties,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type ReactNode, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Nova Section Message Component Props\nexport type NovaSectionMessageProps = SectionMessageProperties & {\n  buttonLabel?: string;\n  description?: string;\n  dismissible?: boolean;\n  href?: string;\n  icon?: ReactNode;\n  linkLabel?: string;\n  onButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n  onClose?: () => void;\n  showIcon?: boolean;\n  title?: string;\n  titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n};\n\n// Main Nova Section Message Component\nexport const NovaSectionMessage = ({\n  buttonLabel,\n  children,\n  description,\n  dismissible = false,\n  href,\n  icon,\n  linkLabel,\n  messageType,\n  onButtonClick,\n  onClose,\n  showIcon = false,\n  title,\n  titleTag = 'h4',\n  ...remainingProps\n}: NovaSectionMessageProps) => {\n  return (\n    <SectionMessage messageType={messageType} {...remainingProps}>\n      {showIcon && <MessageIcon messageType={messageType as Parameters<typeof MessageIcon>[0]['messageType']} />}\n\n      {icon}\n      <UtilityFragment vPaddingBottom={2} vPaddingLeft={2}>\n        <SectionMessageContent>\n          {title && (\n            <Typography tag={titleTag} variant=\"body-2-bold\">\n              {title}\n            </Typography>\n          )}\n          {description && <Typography>{description}</Typography>}\n          {buttonLabel && (\n            <UtilityFragment vMarginRight={linkLabel ? 8 : 0} vMarginTop={8}>\n              <Button colorScheme=\"secondary\" onClick={onButtonClick}>\n                {buttonLabel}\n              </Button>\n            </UtilityFragment>\n          )}\n          {linkLabel && <Link href={href}>{linkLabel}</Link>}\n          {children}\n        </SectionMessageContent>\n      </UtilityFragment>\n\n      {dismissible && (\n        <SectionMessageCloseButton aria-label=\"close\" onClick={onClose}>\n          <VisaCloseTiny />\n        </SectionMessageCloseButton>\n      )}\n    </SectionMessage>\n  );\n};\n\n// export default NovaSectionMessage;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  buttonLabel: string;\n  description: string;\n  dismissible: boolean;\n  href: string;\n  linkLabel: string;\n  messageType: MessageType;\n  showIcon: boolean;\n  title: string;\n  titleTag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n}\n\n// Demo Component\nexport const NovaSectionMessageDemo = () => {\n  const messageTypes: { label: string; value: MessageType }[] = [\n    { label: 'Success', value: 'success' },\n    { label: 'Information', value: 'information' },\n    { label: 'Warning', value: 'warning' },\n    { label: 'Error', value: 'error' },\n    { label: 'Subtle', value: 'subtle' },\n  ];\n\n  const titleTags: { label: string; value: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' }[] = [\n    { label: '1', value: 'h1' },\n    { label: '2', value: 'h2' },\n    { label: '3', value: 'h3' },\n    { label: '4', value: 'h4' },\n    { label: '5', value: 'h5' },\n    { label: '6', value: 'h6' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    buttonLabel: '',\n    description: 'This is required text that describes the section message in more detail.',\n    dismissible: true,\n    href: 'www.visa.com',\n    linkLabel: '',\n    messageType: 'success',\n    showIcon: true,\n    title: 'Success title',\n    titleTag: 'h4',\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  const handleClose = () => {\n    console.log('Section message closed');\n  };\n\n  const handleClick = () => {\n    console.log('Section message button clicked');\n  };\n\n  return (\n    <div>\n      <NovaSectionMessage\n        buttonLabel={customizations.buttonLabel || ''}\n        description={customizations.description || ''}\n        dismissible={customizations.dismissible}\n        href={customizations.href || ''}\n        linkLabel={customizations.linkLabel || ''}\n        messageType={customizations.messageType}\n        onButtonClick={handleClick}\n        onClose={handleClose}\n        showIcon={customizations.showIcon}\n        title={customizations.title || ''}\n        titleTag={customizations.titleTag}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Button label\"\n                onChange={e => handleInputChange('buttonLabel', e.target.value)}\n                value={formValues.buttonLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Href\"\n                onChange={e => handleInputChange('href', e.target.value)}\n                value={formValues.href}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Link label\"\n                onChange={e => handleInputChange('linkLabel', e.target.value)}\n                value={formValues.linkLabel}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Title\"\n                onChange={e => handleInputChange('title', e.target.value)}\n                value={formValues.title}\n              />\n\n              <NovaSelect\n                label=\"Message type\"\n                onChange={e => handleInputChange('messageType', e.target.value as MessageType)}\n                options={messageTypes}\n                value={formValues.messageType}\n              />\n\n              <NovaSelect\n                label=\"Title level\"\n                onChange={e => handleInputChange('titleTag', e.target.value as DemoCustomizations['titleTag'])}\n                options={titleTags}\n                value={formValues.titleTag}\n              />\n\n              <NovaCheckbox\n                label=\"Dismissible\"\n                checked={formValues.dismissible}\n                onChange={e => handleInputChange('dismissible', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Show icon\"\n                checked={formValues.showIcon}\n                onChange={e => handleInputChange('showIcon', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaSectionMessageDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable section message"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Sectionmessage",
          "selector": "<SectionMessage />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Section-level messages providing information about the status of a page or action."
        },
        {
          "order": 2,
          "name": "SectionMessageCloseButton",
          "selector": "<SectionMessageCloseButton />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Close button for section message component."
        },
        {
          "order": 3,
          "name": "Messagecontent",
          "selector": "<MessageContent />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for message content elements."
        }
      ],
      "properties": [
        {
          "name": "messageType",
          "section": "Sectionmessage",
          "data": {
            "name": "messageType",
            "type": "\"subtle\" , \"warning\" , \"error\" , \"information\" , \"success\"",
            "default": "",
            "required": "false",
            "description": "Message Type"
          }
        },
        {
          "name": "tag",
          "section": "Sectionmessage",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "children",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "children",
            "type": "ReactNode",
            "default": "",
            "required": "false",
            "description": "@required"
          }
        },
        {
          "name": "colorScheme",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "SectionMessageCloseButton",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "tag",
          "section": "Messagecontent",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "select",
      "version": "0.0.1",
      "description": "HTML element that allows users to select one option from a list.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default selects",
          "description": "",
          "order": 1
        },
        {
          "name": "Custom selects",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/default-select",
            "github": "apps/workshop/src/examples/components/select/default-select.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { InputContainer, InputControl, Label, Select, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-select';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const DefaultSelect = () => {\n  return (\n    <Utility tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Select id={id} name={`${id}-name`}>\n          <option hidden value=\"\" />\n          {options.map((option, index) => (\n            <option key={`${id}-option-${index}`} value={index}>\n              {option}\n            </option>\n          ))}\n        </Select>\n        <InputControl>\n          <VisaChevronDownTiny />\n        </InputControl>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default select"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/inline-select",
            "github": "apps/workshop/src/examples/components/select/inline-select.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { InputContainer, InputControl, Label, Select, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'inline-select';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const InlineSelect = () => {\n  return (\n    <Utility tag=\"fieldset\" vAlignItems=\"center\" vFlex vFlexRow vGap={6}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Select id={id} name={`${id}-name`}>\n          <option hidden value=\"\" />\n          {options.map((option, index) => (\n            <option key={`${id}-option-${index}`} value={index}>\n              {option}\n            </option>\n          ))}\n        </Select>\n        <InputControl>\n          <VisaChevronDownTiny />\n        </InputControl>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Select with inline label"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/select-with-inline-message",
            "github": "apps/workshop/src/examples/components/select/select-with-inline-message.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { InputContainer, InputControl, InputMessage, Label, Select, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'select-with-inline-message';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const SelectWithInlineMessage = () => {\n  return (\n    <Utility aria-labelledby={`${id}-message`} tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Select aria-describedby={`${id}-message`} id={id} name={`${id}-name`}>\n          <option hidden value=\"\" />\n          {options.map((option, index) => (\n            <option key={`${id}-option-${index}`} value={index}>\n              {option}\n            </option>\n          ))}\n        </Select>\n        <InputControl>\n          <VisaChevronDownTiny />\n        </InputControl>\n      </InputContainer>\n      <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n    </Utility>\n  );\n};\n"
          },
          "name": "Select with inline message"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/error-select",
            "github": "apps/workshop/src/examples/components/select/error-select.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport { useRef, useState, type ChangeEvent, type FormEvent } from 'react';\nimport { Button, InputContainer, InputControl, InputMessage, Label, Select, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'error-select';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const ErrorSelect = () => {\n  const [invalid, setInvalid] = useState(false);\n  const [selectValue, setSelectValue] = useState('');\n  const selectRef = useRef<HTMLSelectElement>(null);\n\n  const onReset = (event: FormEvent) => {\n    event.preventDefault();\n    setInvalid(false);\n    setSelectValue('');\n  };\n  const onSelectChange = (event: ChangeEvent<HTMLSelectElement>) => {\n    const { value } = event.currentTarget;\n    setInvalid(!value);\n    setSelectValue(value);\n  };\n  const onSubmit = (event: FormEvent) => {\n    event.preventDefault();\n    const isInvalid = !selectValue;\n    setInvalid(isInvalid);\n    if (isInvalid) {\n      selectRef.current?.focus();\n    }\n  };\n\n  return (\n    <Utility<'form'> noValidate onReset={onReset} onSubmit={onSubmit} tag=\"form\" vFlex vFlexCol vGap={16}>\n      <Utility aria-labelledby={`${id}-message`} tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Select\n            aria-describedby={`${id}-message`}\n            aria-invalid={invalid}\n            id={id}\n            name=\"full-name\"\n            onChange={onSelectChange}\n            ref={selectRef}\n            required\n            value={selectValue}\n          >\n            <option hidden value=\"\" />\n            {options.map((option, index) => (\n              <option key={`${id}-option-${index}`} value={index}>\n                {option}\n              </option>\n            ))}\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n        {invalid && (\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`}>\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail\n          </InputMessage>\n        )}\n      </Utility>\n      <Utility vFlex vGap={10}>\n        <Button type=\"submit\">Submit</Button>\n        <Button colorScheme=\"secondary\" type=\"reset\">\n          Reset\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Select with error"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/read-only-select",
            "github": "apps/workshop/src/examples/components/select/read-only-select.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { InputContainer, InputControl, Label, Select, Utility } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'read-only-select';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const ReadOnlySelect = () => {\n  return (\n    <Utility tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n      <Label htmlFor={id}>Label (required)</Label>\n      <InputContainer>\n        <Select defaultValue=\"0\" id={id} name={`${id}-name`} aria-readonly={true} required>\n          <option hidden value=\"\" />\n          {options.map((option, index) => (\n            <option disabled key={`${id}-option-${index}`} value={index}>\n              {option}\n            </option>\n          ))}\n        </Select>\n        <InputControl>\n          <VisaChevronDownTiny />\n        </InputControl>\n      </InputContainer>\n    </Utility>\n  );\n};\n"
          },
          "name": "Read-only select"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default selects",
          "url": {
            "iframe": "components/select/disabled-select",
            "github": "apps/workshop/src/examples/components/select/disabled-select.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport { Checkbox, InputContainer, InputControl, InputMessage, Label, Select, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-select';\n\nconst options = ['Option A', 'Option B', 'Option C', 'Option D', 'Option E'];\n\nexport const DisabledSelect = () => {\n  const [disabled, setDisabled] = useState(true);\n\n  return (\n    <Utility vFlex vFlexCol vGap={16}>\n      <Utility aria-labelledby={`${id}-message`} tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n        <Label htmlFor={id}>Label (required)</Label>\n        <InputContainer>\n          <Select aria-describedby={`${id}-message`} disabled={disabled} id={id} name={`${id}-name`}>\n            <option hidden value=\"\" />\n            {options.map((option, index) => (\n              <option key={`${id}-option-${index}`} value={index}>\n                {option}\n              </option>\n            ))}\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n        <InputMessage id={`${id}-message`}>This is optional text that describes the label in more detail.</InputMessage>\n      </Utility>\n      <Utility vAlignItems=\"center\" vFlex vGap={2}>\n        <Checkbox\n          checked={disabled}\n          id={`${id}-demo-checkbox`}\n          onChange={() => {\n            setDisabled(!disabled);\n          }}\n        />\n        <Label htmlFor={`${id}-demo-checkbox`}>Mark select as disabled</Label>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled select"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Custom selects",
          "url": {
            "iframe": "components/select/card-expiration",
            "github": "apps/workshop/src/examples/components/select/card-expiration.tsx"
          },
          "tags": [
            "custom"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  InputContainer,\n  InputControl,\n  InputMessage,\n  Label,\n  Select,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { useState, type ChangeEvent, type FormEvent } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'card-expiration-select';\n\nconst today = new Date();\nconst currentMonth = today.getMonth() + 1;\nconst currentMonthString = currentMonth.toString();\nconst currentYear = today.getFullYear();\nconst currentYearString = currentYear.toString();\n\nconst months = Array.from({ length: 12 }, (_, i) => i + 1);\nconst years = Array.from({ length: 11 }, (_, i) => currentYear + i);\n\nexport const CardExpirationSelect = () => {\n  const [selectedMonth, setSelectedMonth] = useState('');\n  const [selectedYear, setSelectedYear] = useState('');\n  const [invalid, setInvalid] = useState(false);\n\n  const onMonthChange = (event: ChangeEvent<HTMLSelectElement>) => {\n    setSelectedMonth(event.target.value);\n    setInvalid(false);\n  };\n  const onYearChange = (event: ChangeEvent<HTMLSelectElement>) => {\n    setSelectedYear(event.target.value);\n    setInvalid(false);\n  };\n\n  const onSubmit = (event: FormEvent<HTMLFormElement>) => {\n    const isValid = event.currentTarget.checkValidity();\n\n    // If valid, alert with selections\n    if (isValid) alert(`Selected Month: ${selectedMonth}\\nSelected Year: ${selectedYear}`);\n    // If invalid, focus on invalid element\n    else (event.currentTarget.querySelector(':not(fieldset):invalid') as HTMLInputElement)?.focus();\n\n    setInvalid(!isValid);\n    event.preventDefault();\n  };\n\n  return (\n    <Utility<'form'> noValidate onSubmit={onSubmit} tag=\"form\" vFlex vFlexCol vGap={6}>\n      <Utility aria-labelledby={`${id}-message`} tag=\"fieldset\" vFlex vFlexCol vGap={4}>\n        <Label tag=\"legend\">Expires (MM/YY)</Label>\n        <Utility vFlex vFlexRow vAlignItems=\"center\" vGap={6}>\n          {/* Month select */}\n          <InputContainer>\n            <Select\n              aria-describedby={`${id}-message`}\n              aria-invalid={invalid && selectedMonth === ''}\n              aria-label=\"Expiration month\"\n              aria-required={true}\n              autoComplete=\"cc-exp-month\"\n              id={`${id}-month`}\n              name={`${id}-month`}\n              onChange={onMonthChange}\n              required\n              value={selectedMonth}\n            >\n              <option hidden value=\"\" />\n              {months.map(month => (\n                <option\n                  disabled={selectedYear !== '' && selectedYear === currentYearString && month < currentMonth}\n                  key={`card-exp-month-${month}`}\n                  value={month}\n                >\n                  {(month < 10 ? '0' : '') + month}\n                </option>\n              ))}\n            </Select>\n            <InputControl>\n              <VisaChevronDownTiny />\n            </InputControl>\n          </InputContainer>\n\n          <Typography aria-hidden={true} tag=\"span\" variant=\"body-1\">\n            /\n          </Typography>\n\n          {/* Year select */}\n          <InputContainer>\n            <Select\n              aria-describedby={`${id}-message`}\n              aria-invalid={invalid && selectedYear === ''}\n              aria-label=\"Expiration year\"\n              aria-required={true}\n              autoComplete=\"cc-exp-year\"\n              id={`${id}-year`}\n              name={`${id}-year`}\n              onChange={onYearChange}\n              required\n              value={selectedYear}\n            >\n              <option hidden value=\"\" />\n              {years.map(year => (\n                <option\n                  disabled={selectedMonth !== '' && year === currentYear && selectedMonth < currentMonthString}\n                  key={`card-exp-year-${year}`}\n                  value={year}\n                >\n                  {year.toString().substring(2)}\n                </option>\n              ))}\n            </Select>\n            <InputControl>\n              <VisaChevronDownTiny />\n            </InputControl>\n          </InputContainer>\n        </Utility>\n        {invalid && (\n          <InputMessage aria-atomic=\"true\" aria-live=\"assertive\" id={`${id}-message`}>\n            <VisaErrorTiny />\n            This is required text that describes the error in more detail\n          </InputMessage>\n        )}\n      </Utility>\n      <div>\n        <Button type=\"submit\">Submit</Button>\n      </div>\n    </Utility>\n  );\n};\n"
          },
          "name": "Select for card expiration"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Custom selects",
          "url": {
            "iframe": "components/select/reusable",
            "github": "apps/workshop/src/examples/components/select/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputContainer, InputMessage, Label, Select, Utility } from '@visa/nova-react';\nimport { useId, useState, type ComponentPropsWithoutRef, type ComponentPropsWithRef } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Select Option Type\nexport interface NovaSelectOption {\n  disabled?: boolean;\n  hidden?: boolean;\n  label: string;\n  value: ComponentPropsWithoutRef<'option'>['value'];\n}\n\n// Nova Select Component Props\nexport interface NovaSelectProps extends ComponentPropsWithRef<'select'> {\n  disabled?: boolean;\n  id?: string;\n  inline?: boolean;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  options?: NovaSelectOption[];\n  readonly?: boolean;\n  required?: boolean;\n}\n\n// Main Nova Select Component\nexport const NovaSelect = ({\n  disabled = false,\n  id: idProp,\n  inline = false,\n  invalid = false,\n  label = '',\n  message,\n  onChange,\n  options = [],\n  readonly = false,\n  required = false,\n  value,\n  ...remainingSelectProps\n}: NovaSelectProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  return (\n    <Utility vAlignItems={inline ? 'start' : undefined} vFlex vFlexCol={!inline} vFlexWrap vGap={4}>\n      <Label\n        htmlFor={`${id}-select`}\n        id={`${id}-label`}\n        style={\n          inline\n            ? {\n                lineHeight: 'var(--v-input-container-block-size)',\n                textWrap: 'nowrap',\n              }\n            : undefined\n        }\n      >\n        {label} {required ? ' (required)' : ''}\n      </Label>\n      <Utility vFlex vFlexCol vFlexGrow vGap={4}>\n        <InputContainer>\n          <Select\n            aria-describedby={`${id}-message`}\n            aria-invalid={invalid}\n            disabled={disabled || readonly}\n            id={`${id}-select`}\n            onChange={onChange}\n            required={required}\n            value={value}\n            {...remainingSelectProps}\n          >\n            <option hidden></option>\n            {options.map((option, i) => (\n              <option\n                key={`${id}-option-${option.value}-${i}`}\n                disabled={readonly || disabled || option.disabled}\n                hidden={option.hidden}\n                value={option.value}\n              >\n                {option.label}\n              </option>\n            ))}\n          </Select>\n          <VisaChevronDownTiny />\n        </InputContainer>\n        <InputMessage\n          aria-atomic={invalid ? true : undefined}\n          aria-live={invalid ? 'assertive' : undefined}\n          id={`${id}-message`}\n        >\n          {invalid && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </Utility>\n    </Utility>\n  );\n};\n// export default NovaSelect;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  disabled: boolean;\n  errorMessage: string;\n  inline: boolean;\n  invalid: boolean;\n  label: string;\n  message: string;\n  options: string;\n  readonly: boolean;\n  required: boolean;\n}\n\n// Demo Options\nconst demoOptions: NovaSelectOption[] = Array.from({ length: 5 }, (_, i) => ({\n  label: `Option ${i + 1}`,\n  value: i + 1,\n}));\n\n// Demo Component\nexport const NovaSelectDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    inline: false,\n    invalid: false,\n    label: 'Label',\n    message: 'This is optional text that describes the label in more detail.',\n    options: JSON.stringify(demoOptions, null, 4),\n    readonly: false,\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'options'> & { options: NovaSelectOption[] }\n  >({\n    ...defaultCustomizations,\n    options: demoOptions,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.options || '[]') as NovaSelectOption[];\n      setCustomizations({\n        ...formValues,\n        options: parsedOptions,\n      });\n    } catch (error) {\n      console.error('Invalid JSON for options:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      options: demoOptions,\n    });\n  };\n\n  return (\n    <div>\n      <NovaSelect\n        disabled={customizations.disabled}\n        inline={customizations.inline}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : customizations.message}\n        options={customizations.options}\n        readonly={customizations.readonly}\n        required={customizations.required}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Message\"\n                onChange={e => handleInputChange('message', e.target.value)}\n                value={formValues.message}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <NovaInput<'textarea'>\n                blockSize=\"100px\"\n                clearable\n                label=\"Options\"\n                onChange={e => handleInputChange('options', e.target.value)}\n                resizable\n                textarea\n                value={formValues.options}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Inline\"\n                checked={formValues.inline}\n                onChange={e => handleInputChange('inline', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Readonly\"\n                checked={formValues.readonly}\n                onChange={e => handleInputChange('readonly', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaSelectDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable select"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Select",
          "selector": "<Select />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "HTML element that allows users to select one option from a list."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Select",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "select",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "surface",
      "version": "0.0.1",
      "description": "Styles container to be used for alternate backgrounds.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Examples",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/surface/default-surface",
            "github": "apps/workshop/src/examples/components/surface/default-surface.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface } from '@visa/nova-react';\n\nexport const DefaultSurface = () => {\n  return <Surface>Example</Surface>;\n};\n"
          },
          "name": "Default"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Examples",
          "url": {
            "iframe": "components/surface/alternate-surface",
            "github": "apps/workshop/src/examples/components/surface/alternate-surface.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface } from '@visa/nova-react';\n\nexport const AlternateSurface = () => {\n  return <Surface surfaceType=\"alternate\">Example</Surface>;\n};\n"
          },
          "name": "Alternate"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Surface",
          "selector": "<Surface />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Styles container to be used for alternate backgrounds."
        }
      ],
      "properties": [
        {
          "name": "surfaceType",
          "section": "Surface",
          "data": {
            "name": "surfaceType",
            "type": "\"alternate\"",
            "default": "",
            "required": "false",
            "description": "Type of Surface"
          }
        },
        {
          "name": "tag",
          "section": "Surface",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "switch",
      "version": "0.0.1",
      "description": "Binary control that allows users to toggle between two states, such as on/off.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default switches",
          "description": "",
          "order": 1
        },
        {
          "name": "Custom switches",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default switches",
          "url": {
            "iframe": "components/switch/default-switch",
            "github": "apps/workshop/src/examples/components/switch/default-switch.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Switch, SwitchLabel, Utility } from '@visa/nova-react';\n\nconst id = 'default-switch-example';\n\nexport const DefaultSwitch = () => {\n  return (\n    <Utility vFlex vFlexWrap vGap={10} vJustifyContent=\"between\" vMargin={8} style={{ maxInlineSize: '288px' }}>\n      <SwitchLabel htmlFor={`${id}-switch`}>Label</SwitchLabel>\n      <Switch id={`${id}-switch`} name=\"default-switch\" />\n    </Utility>\n  );\n};\n"
          },
          "name": "Default switch"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default switches",
          "url": {
            "iframe": "components/switch/optional-message-switch",
            "github": "apps/workshop/src/examples/components/switch/optional-message-switch.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { InputMessage, Switch, SwitchLabel, Utility } from '@visa/nova-react';\n\nconst id = 'optional-message-switch-example';\n\nexport const OptionalMessageSwitch = () => {\n  return (\n    <Utility\n      vAlignItems=\"center\"\n      vFlex\n      vFlexRow\n      vFlexWrap\n      vGap={10}\n      vJustifyContent=\"between\"\n      vMargin={8}\n      style={{ maxInlineSize: '288px' }}\n    >\n      <Utility vFlex vFlexCol vFlexGrow vGap={2} vJustifyContent=\"between\" style={{ flexBasis: 'min-content' }}>\n        <SwitchLabel htmlFor={`${id}-switch`}>Label</SwitchLabel>\n        <InputMessage id={`${id}-message`}>\n          This is optional text that can be used to describe the label in more detail.\n        </InputMessage>\n      </Utility>\n      <Switch aria-describedby={`${id}-message`} id={`${id}-switch`} name=\"switch-with-message\" />\n    </Utility>\n  );\n};\n"
          },
          "name": "Switch with description"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default switches",
          "url": {
            "iframe": "components/switch/disabled-switch",
            "github": "apps/workshop/src/examples/components/switch/disabled-switch.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Switch, SwitchLabel, Utility } from '@visa/nova-react';\n\nconst id = 'disabled-switch-example';\n\nexport const DisabledSwitch = () => {\n  return (\n    <Utility vFlex vFlexWrap vGap={10} vJustifyContent=\"between\" vMargin={8} style={{ maxInlineSize: '288px' }}>\n      <SwitchLabel htmlFor={`${id}-switch`}>Label</SwitchLabel>\n      <Switch disabled id={`${id}-switch`} name=\"disabled-off-switch\" />\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled switch"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default switches",
          "url": {
            "iframe": "components/switch/disabled-switch-on",
            "github": "apps/workshop/src/examples/components/switch/disabled-switch-on.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Switch, SwitchLabel, Utility } from '@visa/nova-react';\n\nconst id = 'disabled-switch-on-example';\n\nexport const DisabledSwitchOn = () => {\n  return (\n    <Utility vFlex vFlexWrap vGap={10} vJustifyContent=\"between\" vMargin={8} style={{ maxInlineSize: '288px' }}>\n      <SwitchLabel htmlFor={`${id}-switch`}>Label</SwitchLabel>\n      <Switch checked disabled id={`${id}-switch`} name=\"disabled-switch-on\" />\n    </Utility>\n  );\n};\n"
          },
          "name": "Disabled selected switch"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Custom switches",
          "url": {
            "iframe": "components/switch/reusable",
            "github": "apps/workshop/src/examples/components/switch/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaErrorTiny } from '@visa/nova-icons-react';\nimport { Button, InputMessage, Switch, SwitchLabel, Typography, Utility, UtilityFragment } from '@visa/nova-react';\nimport { type ComponentPropsWithRef, useId, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\n\n// Nova Switch Component Props\nexport type NovaSwitchProps = Omit<ComponentPropsWithRef<'input'>, 'type'> & {\n  alignStart?: boolean;\n  description?: string;\n  disabled?: boolean;\n  invalid?: boolean;\n  label?: string;\n  message?: string;\n  required?: boolean;\n};\n\n// Main Nova Switch Component\nexport const NovaSwitch = ({\n  alignStart = false,\n  checked = false,\n  description,\n  disabled = false,\n  id: idProp,\n  invalid = false,\n  label = '',\n  message,\n  onChange,\n  required = false,\n  ...remainingInputProps\n}: NovaSwitchProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  // Calculate aria-describedby\n  const inputDescribedBy =\n    message || description\n      ? [message ? `${id}-message` : '', description ? `${id}-description` : ''].filter(Boolean).join(' ')\n      : undefined;\n\n  const switchInput = (\n    <Switch\n      aria-describedby={inputDescribedBy}\n      aria-required={required ? true : undefined}\n      checked={checked}\n      disabled={disabled}\n      id={`${id}-input`}\n      aria-invalid={invalid}\n      onChange={onChange}\n      required={required}\n      type=\"checkbox\"\n      {...remainingInputProps}\n    />\n  );\n\n  return (\n    <>\n      <Utility\n        vAlignItems=\"center\"\n        vFlex\n        style={{ flexBasis: 'min-content' }}\n        vFlexWrap\n        vGap={10}\n        vJustifyContent=\"between\"\n        vMargin={8}\n      >\n        {alignStart && switchInput}\n        <Utility vFlex style={{ flexBasis: 'min-content' }} vFlexCol vFlexGrow vGap={2} vMarginTop={2}>\n          <SwitchLabel className=\"v-typography-label-large\" htmlFor={`${id}-input`}>\n            {label}\n            {required ? ' (required)' : ''}\n          </SwitchLabel>\n          {description && (\n            <Typography variant=\"body-3\" id={`${id}-description`} tag=\"span\">\n              {description}\n            </Typography>\n          )}\n        </Utility>\n        {!alignStart && switchInput}\n      </Utility>\n\n      <UtilityFragment vMarginTop={4}>\n        <InputMessage\n          aria-atomic={invalid ? true : undefined}\n          aria-live={invalid ? 'assertive' : undefined}\n          id={`${id}-message`}\n        >\n          {invalid && message && <VisaErrorTiny />}\n          {message && message}\n        </InputMessage>\n      </UtilityFragment>\n    </>\n  );\n};\n\n// export default NovaSwitch;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  alignStart: boolean;\n  description: string;\n  disabled: boolean;\n  errorMessage: string;\n  invalid: boolean;\n  label: string;\n  required: boolean;\n}\n\n// Demo Component\nconst NovaSwitchDemo = () => {\n  const defaultCustomizations: DemoCustomizations = {\n    alignStart: false,\n    description: 'This is optional text that describes the label in more detail.',\n    disabled: false,\n    errorMessage: 'This is required text that describes the error in more detail.',\n    invalid: false,\n    label: 'Label',\n    required: false,\n  };\n\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  return (\n    <div>\n      <NovaSwitch\n        alignStart={customizations.alignStart}\n        description={customizations.description || ''}\n        disabled={customizations.disabled}\n        invalid={customizations.invalid}\n        label={customizations.label || ''}\n        message={customizations.invalid ? customizations.errorMessage : undefined}\n        required={customizations.required}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                label=\"Description\"\n                onChange={e => handleInputChange('description', e.target.value)}\n                value={formValues.description}\n              />\n\n              <NovaInput\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                value={formValues.label}\n              />\n\n              <NovaInput\n                label=\"Error message\"\n                onChange={e => handleInputChange('errorMessage', e.target.value)}\n                value={formValues.errorMessage}\n              />\n\n              <NovaCheckbox\n                label=\"Align start\"\n                checked={formValues.alignStart}\n                onChange={e => handleInputChange('alignStart', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Disabled\"\n                checked={formValues.disabled}\n                onChange={e => handleInputChange('disabled', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Invalid\"\n                checked={formValues.invalid}\n                onChange={e => handleInputChange('invalid', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Required\"\n                checked={formValues.required}\n                onChange={e => handleInputChange('required', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaSwitchDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable switch"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Switch",
          "selector": "<Switch />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Binary control that allows users to toggle between two states, such as on/off."
        },
        {
          "order": 2,
          "name": "Switchlabel",
          "selector": "<SwitchLabel />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Label to be used with switch component."
        }
      ],
      "properties": [
        {
          "name": "tag",
          "section": "Switch",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "input",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "colorScheme",
          "section": "Switchlabel",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Switchlabel",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Switchlabel",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "table",
      "version": "0.0.1",
      "description": "Grid that organizes information, enabling data interaction, manipulation, and criteria-based analysis using columns and rows.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Static tables with banded rows",
          "description": "",
          "order": 1
        },
        {
          "name": "Static tables without banded rows",
          "description": "",
          "order": 2
        },
        {
          "name": "Static tables with group headers",
          "description": "",
          "order": 3
        },
        {
          "name": "Key value static tables",
          "description": "",
          "order": 4
        },
        {
          "name": "Custom tables",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with banded rows",
          "url": {
            "iframe": "components/table/large-padding-banded-table",
            "github": "apps/workshop/src/examples/components/table/large-padding-banded-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const LargePaddingBandedTable = () => {\n  return (\n    <Table alternate tableSize=\"large\">\n      <ScreenReader tag=\"caption\">Table with large padding and banded rows.</ScreenReader>\n      <Thead>\n        <Tr>\n          <Th scope=\"col\">Column A</Th>\n          <Th scope=\"col\">Column B</Th>\n          <Th scope=\"col\">Column C</Th>\n          <Th scope=\"col\">Column D</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\">A1</Th>\n          <Td>B1</Td>\n          <Td>C1</Td>\n          <Td>D1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A2</Th>\n          <Td>B2</Td>\n          <Td>C2</Td>\n          <Td>D2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A3</Th>\n          <Td>B3</Td>\n          <Td>C3</Td>\n          <Td>D3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Large padding table with banded rows"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with banded rows",
          "url": {
            "iframe": "components/table/medium-padding-banded-table",
            "github": "apps/workshop/src/examples/components/table/medium-padding-banded-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const MediumPaddingBandedTable = () => {\n  return (\n    <Table alternate>\n      <ScreenReader tag=\"caption\">Table with medium padding and banded rows.</ScreenReader>\n      <Thead>\n        <Tr>\n          <Th scope=\"col\">Column A</Th>\n          <Th scope=\"col\">Column B</Th>\n          <Th scope=\"col\">Column C</Th>\n          <Th scope=\"col\">Column D</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\">A1</Th>\n          <Td>B1</Td>\n          <Td>C1</Td>\n          <Td>D1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A2</Th>\n          <Td>B2</Td>\n          <Td>C2</Td>\n          <Td>D2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A3</Th>\n          <Td>B3</Td>\n          <Td>C3</Td>\n          <Td>D3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Medium padding table with banded rows"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with banded rows",
          "url": {
            "iframe": "components/table/small-padding-banded-table",
            "github": "apps/workshop/src/examples/components/table/small-padding-banded-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const SmallPaddingBandedTable = () => {\n  return (\n    <Table alternate tableSize=\"small\">\n      <ScreenReader tag=\"caption\">Table with compact padding and banded rows.</ScreenReader>\n      <Thead>\n        <Tr>\n          <Th scope=\"col\">Column A</Th>\n          <Th scope=\"col\">Column B</Th>\n          <Th scope=\"col\">Column C</Th>\n          <Th scope=\"col\">Column D</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\">A1</Th>\n          <Td>B1</Td>\n          <Td>C1</Td>\n          <Td>D1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A2</Th>\n          <Td>B2</Td>\n          <Td>C2</Td>\n          <Td>D2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A3</Th>\n          <Td>B3</Td>\n          <Td>C3</Td>\n          <Td>D3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Small padding table with banded rows"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with banded rows",
          "url": {
            "iframe": "components/table/scroll-table",
            "github": "apps/workshop/src/examples/components/table/scroll-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\nimport { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const ScrollTable = () => {\n  return (\n    <TableWrapper\n      style={{ '--v-table-wrapper-block-size': '288px', '--v-table-wrapper-inline-size': '576px' } as CSSProperties}\n      tabIndex={0}\n    >\n      <Table alternate>\n        <ScreenReader tag=\"caption\">Table with extra data added to demo scrollable content.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Th scope=\"col\">Column A</Th>\n            <Th scope=\"col\">Column B</Th>\n            <Th scope=\"col\">Column C</Th>\n            <Th scope=\"col\">Column D</Th>\n            <Th scope=\"col\">Column E</Th>\n            <Th scope=\"col\">Column F</Th>\n            <Th scope=\"col\">Column G</Th>\n            <Th scope=\"col\">Column H</Th>\n            <Th scope=\"col\">Column I</Th>\n            <Th scope=\"col\">Column J</Th>\n            <Th scope=\"col\">Column K</Th>\n            <Th scope=\"col\">Column L</Th>\n          </Tr>\n        </Thead>\n        <Tbody>\n          <Tr>\n            <Th scope=\"row\">A1</Th>\n            <Td>B1</Td>\n            <Td>C1</Td>\n            <Td>D1</Td>\n            <Td>E1</Td>\n            <Td>F1</Td>\n            <Td>G1</Td>\n            <Td>H1</Td>\n            <Td>I1</Td>\n            <Td>J1</Td>\n            <Td>K1</Td>\n            <Td>L1</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A2</Th>\n            <Td>B2</Td>\n            <Td>C2</Td>\n            <Td>D2</Td>\n            <Td>E2</Td>\n            <Td>F2</Td>\n            <Td>G2</Td>\n            <Td>H2</Td>\n            <Td>I2</Td>\n            <Td>J2</Td>\n            <Td>K2</Td>\n            <Td>L2</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A3</Th>\n            <Td>B3</Td>\n            <Td>C3</Td>\n            <Td>D3</Td>\n            <Td>E3</Td>\n            <Td>F3</Td>\n            <Td>G3</Td>\n            <Td>H3</Td>\n            <Td>I3</Td>\n            <Td>J3</Td>\n            <Td>K3</Td>\n            <Td>L3</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A4</Th>\n            <Td>B4</Td>\n            <Td>C4</Td>\n            <Td>D4</Td>\n            <Td>E4</Td>\n            <Td>F4</Td>\n            <Td>G4</Td>\n            <Td>H4</Td>\n            <Td>I4</Td>\n            <Td>J4</Td>\n            <Td>K4</Td>\n            <Td>L4</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A5</Th>\n            <Td>B5</Td>\n            <Td>C5</Td>\n            <Td>D5</Td>\n            <Td>E5</Td>\n            <Td>F5</Td>\n            <Td>G5</Td>\n            <Td>H5</Td>\n            <Td>I5</Td>\n            <Td>J5</Td>\n            <Td>K5</Td>\n            <Td>L5</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A6</Th>\n            <Td>B6</Td>\n            <Td>C6</Td>\n            <Td>D6</Td>\n            <Td>E6</Td>\n            <Td>F6</Td>\n            <Td>G6</Td>\n            <Td>H6</Td>\n            <Td>I6</Td>\n            <Td>J6</Td>\n            <Td>K6</Td>\n            <Td>L6</Td>\n          </Tr>\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n"
          },
          "name": "Table with scrollbars and banded rows"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables without banded rows",
          "url": {
            "iframe": "components/table/lined-rows-table",
            "github": "apps/workshop/src/examples/components/table/lined-rows-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const LinedRowsTable = () => {\n  return (\n    <Table borderBlock>\n      <ScreenReader tag=\"caption\">Table with lined rows.</ScreenReader>\n      <Thead>\n        <Tr>\n          <Th scope=\"col\">Column A</Th>\n          <Th scope=\"col\">Column B</Th>\n          <Th scope=\"col\">Column C</Th>\n          <Th scope=\"col\">Column D</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\">A1</Th>\n          <Td>B1</Td>\n          <Td>C1</Td>\n          <Td>D1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A2</Th>\n          <Td>B2</Td>\n          <Td>C2</Td>\n          <Td>D2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\">A3</Th>\n          <Td>B3</Td>\n          <Td>C3</Td>\n          <Td>D3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Table with lined rows"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables without banded rows",
          "url": {
            "iframe": "components/table/outer-border-column-row-table",
            "github": "apps/workshop/src/examples/components/table/outer-border-column-row-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const OuterBorderColumnRowDividerTable = () => {\n  return (\n    <TableWrapper>\n      <Table border>\n        <ScreenReader tag=\"caption\">Table with outer borders on column and row dividers.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Th scope=\"col\">Column A</Th>\n            <Th scope=\"col\">Column B</Th>\n            <Th scope=\"col\">Column C</Th>\n            <Th scope=\"col\">Column D</Th>\n          </Tr>\n        </Thead>\n        <Tbody>\n          <Tr>\n            <Th scope=\"row\">A1</Th>\n            <Td>B1</Td>\n            <Td>C1</Td>\n            <Td>D1</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A2</Th>\n            <Td>B2</Td>\n            <Td>C2</Td>\n            <Td>D2</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A3</Th>\n            <Td>B3</Td>\n            <Td>C3</Td>\n            <Td>D3</Td>\n          </Tr>\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n"
          },
          "name": "Table with outer border, column, and row dividers"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables without banded rows",
          "url": {
            "iframe": "components/table/outer-border-subtle-header-table",
            "github": "apps/workshop/src/examples/components/table/outer-border-subtle-header-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const OuterBorderSubtleHeaderTable = () => {\n  return (\n    <TableWrapper>\n      <Table border subtle>\n        <ScreenReader tag=\"caption\">Table with outer borders and subtle headers.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Th scope=\"col\">Column A</Th>\n            <Th scope=\"col\">Column B</Th>\n            <Th scope=\"col\">Column C</Th>\n            <Th scope=\"col\">Column D</Th>\n          </Tr>\n        </Thead>\n        <Tbody>\n          <Tr>\n            <Th scope=\"row\">A1</Th>\n            <Td>B1</Td>\n            <Td>C1</Td>\n            <Td>D1</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A2</Th>\n            <Td>B2</Td>\n            <Td>C2</Td>\n            <Td>D2</Td>\n          </Tr>\n          <Tr>\n            <Th scope=\"row\">A3</Th>\n            <Td>B3</Td>\n            <Td>C3</Td>\n            <Td>D3</Td>\n          </Tr>\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n"
          },
          "name": "Table with outer border and subtle headers"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with group headers",
          "url": {
            "iframe": "components/table/group-headers-table",
            "github": "apps/workshop/src/examples/components/table/group-headers-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const GroupHeadersTable = () => {\n  return (\n    <Table border>\n      <ScreenReader tag=\"caption\">Table with group headers.</ScreenReader>\n      <Thead>\n        <Tr className=\"v-typography-overline\">\n          <Th alternate colSpan={2} id=\"group-header-1\">\n            Group header 1\n          </Th>\n          <Th alternate colSpan={2} id=\"group-header-2\">\n            Group header 2\n          </Th>\n        </Tr>\n        <Tr>\n          <Th scope=\"col\" id=\"column-a\">Column A</Th>\n          <Th scope=\"col\" id=\"column-b\">Column B</Th>\n          <Th scope=\"col\" id=\"column-c\">Column C</Th>\n          <Th scope=\"col\" id=\"column-d\">Column D</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\" id=\"row-1\" headers=\"group-header-1 column-a\">A1</Th>\n          <Td headers=\"group-header-1 column-b row-1\">B1</Td>\n          <Td headers=\"group-header-2 column-c row-1\">C1</Td>\n          <Td headers=\"group-header-2 column-d row-1\">D1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\" id=\"row-2\" headers=\"group-header-1 column-a\">A2</Th>\n          <Td headers=\"group-header-1 column-b row-2\">B2</Td>\n          <Td headers=\"group-header-2 column-c row-2\">C2</Td>\n          <Td headers=\"group-header-2 column-d row-2\">D2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\" id=\"row-3\" headers=\"group-header-1 column-a\">A3</Th>\n          <Td headers=\"group-header-1 column-b row-3\">B3</Td>\n          <Td headers=\"group-header-2 column-c row-3\">C3</Td>\n          <Td headers=\"group-header-2 column-d row-3\">D3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Table with group headers"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Static tables with group headers",
          "url": {
            "iframe": "components/table/group-headers-empty-cell-table",
            "github": "apps/workshop/src/examples/components/table/group-headers-empty-cell-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Th, Thead, Tr } from '@visa/nova-react';\n\nexport const GroupHeadersEmptyCellTable = () => {\n  return (\n    <Table border>\n      <ScreenReader tag=\"caption\">Table with group headers and an empty cell.</ScreenReader>\n      <Thead>\n        <Tr className=\"v-typography-overline\">\n          <Th alternate tag=\"td\" />\n          <Th alternate colSpan={1} id=\"e-group-header-1\">\n            Group header 1\n          </Th>\n          <Th alternate colSpan={1} id=\"e-group-header-2\">\n            Group header 2\n          </Th>\n        </Tr>\n        <Tr>\n          <Th scope=\"col\" id=\"e-column-a\">Column A</Th>\n          <Th scope=\"col\" id=\"e-column-b\">Column B</Th>\n          <Th scope=\"col\" id=\"e-column-c\">Column C</Th>\n        </Tr>\n      </Thead>\n      <Tbody>\n        <Tr>\n          <Th scope=\"row\" id=\"e-row-1\" headers=\"e-column-a\">A1</Th>\n          <Td headers=\"e-group-header-1 e-column-b e-row-1\">B1</Td>\n          <Td headers=\"e-group-header-2 e-column-c e-row-1\">C1</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\" id=\"e-row-2\" headers=\"e-column-a\">A2</Th>\n          <Td headers=\"e-group-header-1 e-column-b e-row-2\">B2</Td>\n          <Td headers=\"e-group-header-2 e-column-c e-row-2\">C2</Td>\n        </Tr>\n        <Tr>\n          <Th scope=\"row\" id=\"e-row-3\" headers=\"e-column-a\">A3</Th>\n          <Td headers=\"e-group-header-1 e-column-b e-row-3\">B3</Td>\n          <Td headers=\"e-group-header-2 e-column-c e-row-3\">C3</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Table with group headers with empty cell"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Key value static tables",
          "url": {
            "iframe": "components/table/key-value-banded-table",
            "github": "apps/workshop/src/examples/components/table/key-value-banded-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, Tbody, Td, Tr } from '@visa/nova-react';\n\nexport const KeyValueBandedTable = () => {\n  return (\n    <Table alternate keyValue>\n      <ScreenReader tag=\"caption\">Table with banded key-value pairs.</ScreenReader>\n      <Tbody>\n        <Tr>\n          <th className=\"v-td\" scope=\"row\">\n            Key 1\n          </th>\n          <Td>Value 1</Td>\n        </Tr>\n        <Tr>\n          <th className=\"v-td\" scope=\"row\">\n            Key 2\n          </th>\n          <Td>Value 2</Td>\n        </Tr>\n        <Tr>\n          <th className=\"v-td\" scope=\"row\">\n            Key 3\n          </th>\n          <Td>Value 3</Td>\n        </Tr>\n        <Tr>\n          <th className=\"v-td\" scope=\"row\">\n            Key 4\n          </th>\n          <Td>Value 4</Td>\n        </Tr>\n      </Tbody>\n    </Table>\n  );\n};\n"
          },
          "name": "Key value table with banded rows"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Key value static tables",
          "url": {
            "iframe": "components/table/key-value-lined-table",
            "github": "apps/workshop/src/examples/components/table/key-value-lined-table.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { ScreenReader, Table, TableWrapper, Tbody, Td, Tr } from '@visa/nova-react';\n\nexport const KeyValueLinedTable = () => {\n  return (\n    <TableWrapper>\n      <Table keyValue border>\n        <ScreenReader tag=\"caption\">Table with lined key-value pairs.</ScreenReader>\n        <Tbody>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 1\n            </th>\n            <Td>Value 1</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 2\n            </th>\n            <Td>Value 2</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 3\n            </th>\n            <Td>Value 3</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 4\n            </th>\n            <Td>Value 4</Td>\n          </Tr>\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n"
          },
          "name": "Key value table with lined rows"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tables",
          "url": {
            "iframe": "components/table/reusable",
            "github": "apps/workshop/src/examples/components/table/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaArrowDownTiny, VisaArrowUpTiny, VisaSortableTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  ScreenReader,\n  Table,\n  type TableProperties,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n\n// Types\nexport type NovaTableBaseRow = object;\n\nexport interface NovaTableSort<RowData extends NovaTableBaseRow = NovaTableBaseRow> {\n  ascending?: boolean;\n  key?: keyof RowData | string;\n}\n\nexport interface NovaTableColumn<RowData extends NovaTableBaseRow = NovaTableBaseRow> {\n  activeTypographyStyle?: boolean;\n  colspan?: number;\n  groupHeader?: boolean;\n  iconString?: string;\n  inputs?: Record<string, unknown>;\n  key: keyof RowData | string;\n  rowRender?: (rowData: RowData, index: number) => ReactNode;\n  sortable?: boolean;\n  title?: string;\n  titleRender?: (index: number) => ReactNode;\n  /**\n   * Transform displayed column data\n   * NOTE: it is preferable to do this only once when the data gets loaded in, not every render\n   */\n  transform?: (data: RowData) => string;\n}\n\n// Nova Table Component Props\nexport interface NovaTableProperties<RowData extends NovaTableBaseRow = NovaTableBaseRow> extends TableProperties {\n  caption: string;\n  columns?: NovaTableColumn<RowData>[];\n  emptyRowsMessage?: string;\n  headerColumns?: NovaTableColumn<RowData>[];\n  loading?: boolean;\n  onSortChange?: (sort: NovaTableSort<RowData>) => void;\n  rows?: RowData[];\n  rowIdKey?: keyof RowData;\n  sort?: NovaTableSort<RowData>;\n}\n\n// Main Nova Table Component\nexport const NovaTable = <RowData extends NovaTableBaseRow = { id: string }>({\n  caption,\n  children,\n  columns = [],\n  emptyRowsMessage = 'No results found',\n  headerColumns = [],\n  id: idProp,\n  keyValue = false,\n  loading = false,\n  onSortChange,\n  rows = [],\n  rowIdKey = 'id' as keyof RowData,\n  sort,\n  ...remainingProps\n}: NovaTableProperties<RowData>) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n\n  const handleSort = (column: NovaTableColumn<RowData>) => {\n    if (column.key === undefined || !column.sortable) return;\n    const newSort: NovaTableSort<RowData> = {\n      ascending: column.key === sort?.key ? !sort?.ascending : true,\n      key: column.key,\n    };\n    onSortChange?.(newSort);\n  };\n\n  return (\n    <TableWrapper>\n      <Table id={`${id}-table`} keyValue={keyValue} {...remainingProps}>\n        <ScreenReader tag=\"caption\">{caption}</ScreenReader>\n\n        {!keyValue && (\n          <Thead>\n            {headerColumns.length > 0 && (\n              <Tr>\n                {headerColumns.map((column, idx) => (\n                  <Th\n                    alternate={column.groupHeader}\n                    key={`header-column-${column.key?.toString() || ''}-${idx}`}\n                    colSpan={column.colspan}\n                    scope=\"col\"\n                  >\n                    {column.titleRender ? column.titleRender(idx) : null}\n                    {column.title}\n                  </Th>\n                ))}\n              </Tr>\n            )}\n            <Tr>\n              {columns.map((column, idx) => (\n                <Th\n                  alternate={column.groupHeader}\n                  aria-sort={column.key === sort?.key ? (sort?.ascending ? 'ascending' : 'descending') : undefined}\n                  key={`header-column-${column.key?.toString() || ''}-${idx}`}\n                  colSpan={column.colspan}\n                  scope=\"col\"\n                >\n                  {column.title}\n                  {column.sortable && (\n                    <Button\n                      aria-label={column.key === sort?.key || !sort?.ascending ? 'sort ascending' : 'sort descending'}\n                      buttonSize=\"small\"\n                      colorScheme=\"tertiary\"\n                      iconButton\n                      onClick={() => handleSort(column)}\n                    >\n                      {column.key !== sort?.key || sort?.ascending === undefined ? (\n                        <VisaSortableTiny />\n                      ) : sort?.ascending ? (\n                        <VisaArrowUpTiny />\n                      ) : (\n                        <VisaArrowDownTiny />\n                      )}\n                    </Button>\n                  )}\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n        )}\n\n        <Tbody>\n          {loading ? (\n            <Tr>\n              <Td colSpan={columns.length}>Loading...</Td>\n            </Tr>\n          ) : rows.length ? (\n            rows.map((row, index) => (\n              <Tr key={`${id}-row-${row[rowIdKey]}-${index}`}>\n                {columns.map((column, colIdx) => {\n                  return (\n                    <UtilityFragment key={`${id}-cell-${row[rowIdKey]}-${column.key.toString()}-${colIdx}`}>\n                      {colIdx === 0 ? (\n                        <Th scope=\"row\" >\n                          {column.rowRender ? column.rowRender(row, index) : (row[column.key as keyof RowData] as string)}\n                        </Th>\n                      ) : (\n                        <Td>\n                          {column.rowRender ? column.rowRender(row, index) : (row[column.key as keyof RowData] as string)}\n                        </Td>\n                      )}\n                    </UtilityFragment>\n                  );\n                })}\n              </Tr>\n            ))\n          ) : emptyRowsMessage ? (\n            <Tr>\n              <Td colSpan={columns.length}>\n                <UtilityFragment vFlex vJustifyContent=\"center\" style={{ padding: '20px', textAlign: 'center' }}>\n                  <Typography variant=\"body-2-bold\">{emptyRowsMessage}</Typography>\n                </UtilityFragment>\n              </Td>\n            </Tr>\n          ) : (\n            <></>\n          )}\n        </Tbody>\n      </Table>\n      {children}\n    </TableWrapper>\n  );\n};\n\n// export default NovaTable;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Types\nexport type DemoRow = {\n  'column-a': number | string;\n  'column-b': number | string;\n  'column-c': number | string;\n  'column-d': number | string;\n} & NovaTableBaseRow;\n\nexport const demoColumns: NovaTableColumn<DemoRow>[] = [\n  { key: 'column-a', title: 'Column A', sortable: false },\n  { key: 'column-b', title: 'Column B', sortable: false },\n  { key: 'column-c', title: 'Column C', sortable: false },\n  { key: 'column-d', title: 'Column D', sortable: false },\n];\n\nexport const demoHeaderColumns: NovaTableColumn<DemoRow>[] = [\n  { colspan: 2, key: 'group-header-1', title: 'Group header 1' },\n  { colspan: 2, key: 'group-header-2', title: 'Group header 2' },\n];\n\nexport const demoRows: DemoRow[] = Array.from({ length: 3 }, (_, i) => ({\n  id: i + 1,\n  'column-a': `A${i + 1}`,\n  'column-b': `B${i + 1}`,\n  'column-c': `C${i + 1}`,\n  'column-d': `D${i + 1}`,\n}));\n\n// Demo Component Types\ninterface DemoCustomizations {\n  alternate: boolean;\n  border: boolean;\n  borderBlock: boolean;\n  caption: string;\n  columns: string;\n  headerColumns: string;\n  keyValue: boolean;\n  loading: boolean;\n  rows: string;\n  showHeaderColumns: boolean;\n  subtle: boolean;\n  tableSize: 'large' | 'medium' | 'small';\n}\n\n// Demo Component\nexport const NovaTableDemo = () => {\n  const tableSizes: { label: string; value: DemoCustomizations['tableSize'] }[] = [\n    { label: 'Small', value: 'small' },\n    { label: 'Medium', value: 'medium' },\n    { label: 'Large', value: 'large' },\n  ];\n\n  const defaultCustomizations: DemoCustomizations = {\n    alternate: true,\n    border: false,\n    borderBlock: false,\n    caption: 'This is required text that describes the table in more detail.',\n    columns: JSON.stringify(demoColumns, null, 4),\n    headerColumns: JSON.stringify(demoHeaderColumns, null, 4),\n    keyValue: false,\n    loading: false,\n    rows: JSON.stringify(demoRows, null, 4),\n    showHeaderColumns: false,\n    subtle: false,\n    tableSize: 'medium',\n  };\n\n  const [customizations, setCustomizations] = useState<\n    Omit<DemoCustomizations, 'columns' | 'headerColumns' | 'rows'> & {\n      columns: NovaTableColumn<DemoRow>[];\n      headerColumns: NovaTableColumn<DemoRow>[];\n      rows: DemoRow[];\n    }\n  >({\n    ...defaultCustomizations,\n    columns: demoColumns,\n    headerColumns: demoHeaderColumns,\n    rows: demoRows,\n  });\n\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    try {\n      const parsedColumns = JSON.parse(formValues.columns || '[]') as NovaTableColumn<DemoRow>[];\n      const parsedHeaderColumns = JSON.parse(formValues.headerColumns || '[]') as NovaTableColumn<DemoRow>[];\n      const parsedRows = JSON.parse(formValues.rows || '[]') as DemoRow[];\n      setCustomizations({\n        ...formValues,\n        columns: parsedColumns,\n        headerColumns: parsedHeaderColumns,\n        rows: parsedRows,\n      });\n    } catch (error) {\n      console.error('Invalid JSON:', error);\n    }\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      columns: demoColumns,\n      headerColumns: demoHeaderColumns,\n      rows: demoRows,\n    });\n  };\n\n  const handleSortChange = (sort: NovaTableSort<DemoRow>) => {\n    console.log('Sort changed:', JSON.stringify(sort));\n  };\n\n  const { headerColumns, showHeaderColumns, ...customizationProps } = customizations;\n\n  return (\n    <div>\n      <NovaTable\n        {...customizationProps}\n        onSortChange={handleSortChange}\n        id=\"demo-reusable-table\"\n        headerColumns={showHeaderColumns ? headerColumns : []}\n      />\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Caption\"\n                onChange={e => handleInputChange('caption', e.target.value)}\n                value={formValues.caption}\n              />\n\n              <NovaInput<'textarea'>\n                fixed={false}\n                label=\"Columns\"\n                onChange={e => handleInputChange('columns', e.target.value)}\n                style={{ blockSize: '100px' }}\n                textarea\n                value={formValues.columns}\n              />\n\n              {customizations.showHeaderColumns && (\n                <NovaInput<'textarea'>\n                  fixed={false}\n                  label=\"Header columns\"\n                  onChange={e => handleInputChange('headerColumns', e.target.value)}\n                  style={{ blockSize: '100px' }}\n                  textarea\n                  value={formValues.headerColumns}\n                />\n              )}\n\n              <NovaInput<'textarea'>\n                fixed={false}\n                label=\"Rows\"\n                onChange={e => handleInputChange('rows', e.target.value)}\n                style={{ blockSize: '100px' }}\n                textarea\n                value={formValues.rows}\n              />\n\n              <NovaSelect\n                label=\"Table size\"\n                onChange={e => handleInputChange('tableSize', e.target.value)}\n                options={tableSizes}\n                value={formValues.tableSize}\n              />\n\n              <NovaCheckbox\n                label=\"Alternate\"\n                checked={formValues.alternate}\n                onChange={e => handleInputChange('alternate', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Border\"\n                checked={formValues.border}\n                onChange={e => handleInputChange('border', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Border block\"\n                checked={formValues.borderBlock}\n                onChange={e => handleInputChange('borderBlock', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Key value\"\n                checked={formValues.keyValue}\n                onChange={e => handleInputChange('keyValue', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Loading\"\n                checked={formValues.loading}\n                onChange={e => handleInputChange('loading', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Show header columns\"\n                checked={formValues.showHeaderColumns}\n                onChange={e => handleInputChange('showHeaderColumns', e.target.checked)}\n              />\n\n              <NovaCheckbox\n                label=\"Subtle\"\n                checked={formValues.subtle}\n                onChange={e => handleInputChange('subtle', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaTableDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable table"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Table",
          "selector": "<Table />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Grid that organizes information, enabling data interaction, manipulation, and criteria-based analysis using columns and rows."
        },
        {
          "order": 2,
          "name": "Tablewrapper",
          "selector": "<TableWrapper />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Container for a table that adds a border with a curved radius to the table."
        },
        {
          "order": 3,
          "name": "Tbody",
          "selector": "<Tbody />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Table body component that contains all the tr and td cells."
        },
        {
          "order": 4,
          "name": "Td",
          "selector": "<Td />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Table data cell component typically used for displaying data and content."
        },
        {
          "order": 5,
          "name": "Th",
          "selector": "<Th />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Table header cell component usually used for titles and column/row descriptions."
        },
        {
          "order": 6,
          "name": "Thead",
          "selector": "<Thead />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Table head component that contains all the th cells."
        },
        {
          "order": 7,
          "name": "Tr",
          "selector": "<Tr />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Table row component."
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Table",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alt"
          }
        },
        {
          "name": "border",
          "section": "Table",
          "data": {
            "name": "border",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Borders all around the table and cells"
          }
        },
        {
          "name": "borderBlock",
          "section": "Table",
          "data": {
            "name": "borderBlock",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Borders only separating the rows"
          }
        },
        {
          "name": "keyValue",
          "section": "Table",
          "data": {
            "name": "keyValue",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Key value pairs where text for the first column is bold."
          }
        },
        {
          "name": "subtle",
          "section": "Table",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle header"
          }
        },
        {
          "name": "tableSize",
          "section": "Table",
          "data": {
            "name": "tableSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Padding size for the table"
          }
        },
        {
          "name": "tag",
          "section": "Tablewrapper",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "Th",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alt"
          }
        },
        {
          "name": "tag",
          "section": "Th",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "th",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "tabs",
      "version": "0.0.1",
      "description": "Organizational element that separates content and allows users to switch between views.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Vertical tabs",
          "description": "",
          "order": 1
        },
        {
          "name": "Horizontal tabs",
          "description": "",
          "order": 2
        },
        {
          "name": "Stacked Tabs",
          "description": "",
          "order": 3
        },
        {
          "name": "Custom tabs",
          "description": "",
          "order": 4
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical tabs",
          "url": {
            "iframe": "components/tabs/default-vertical-tabs",
            "github": "apps/workshop/src/examples/components/tabs/default-vertical-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, UtilityFragment, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-vertical-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const DefaultVerticalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'vertical', defaultSelected: 0 });\n\n  return (\n    <Utility vFlex vFlexWrap vGap={8}>\n      <Tabs onKeyDown={onKeyNavigation} orientation=\"vertical\" role=\"tablist\" style={{ flexBasis: '30%' }}>\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vFlex vFlexGrow vElevation=\"inset\">\n        <UtilityFragment vPadding={10}>\n          <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\">\n            <span>{tabsContent[selectedIndex]?.text}</span>\n          </Surface>\n        </UtilityFragment>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default vertical tablist"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical tabs",
          "url": {
            "iframe": "components/tabs/icon-vertical-tabs",
            "github": "apps/workshop/src/examples/components/tabs/icon-vertical-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaStatisticsTiny, VisaTopicTiny, VisaEmailTiny, VisaHomeTiny } from '@visa/nova-icons-react';\nimport { Button, Surface, Tab, Tabs, Utility, UtilityFragment, useTabs } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-icon-vertical-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    icon: <VisaStatisticsTiny />,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    icon: <VisaTopicTiny />,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    icon: <VisaEmailTiny />,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    icon: <VisaHomeTiny />,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const IconVerticalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'vertical', defaultSelected: 0 });\n\n  return (\n    <Utility vFlex vFlexWrap vGap={8}>\n      <Tabs onKeyDown={onKeyNavigation} orientation=\"vertical\" role=\"tablist\" style={{ flexBasis: '30%' }}>\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n              style={{ minInlineSize: 'max-content' } as CSSProperties}\n            >\n              {tabContent.icon}\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vFlex vFlexGrow vElevation=\"inset\">\n        <UtilityFragment vPadding={10}>\n          <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\">\n            <span>{tabsContent[selectedIndex]?.text}</span>\n          </Surface>\n        </UtilityFragment>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Vertical tablist with icon"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical tabs",
          "url": {
            "iframe": "components/tabs/disabled-vertical-tabs",
            "github": "apps/workshop/src/examples/components/tabs/disabled-vertical-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, UtilityFragment, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-disabled-vertical-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    disabled: true,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const DisabledVerticalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'vertical', defaultSelected: 0 });\n\n  return (\n    <Utility vFlex vFlexWrap vGap={8}>\n      <Tabs onKeyDown={onKeyNavigation} orientation=\"vertical\" role=\"tablist\" style={{ flexBasis: '30%' }}>\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              disabled={tabContent.disabled}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vFlex vFlexGrow vElevation=\"inset\">\n        <UtilityFragment vPadding={10}>\n          <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\">\n            <span>{tabsContent[selectedIndex]?.text}</span>\n          </Surface>\n        </UtilityFragment>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Vertical tablist with disabled tab"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical tabs",
          "url": {
            "iframe": "components/tabs/vertical-tab-with-menu",
            "github": "apps/workshop/src/examples/components/tabs/vertical-tab-with-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Tab, Tabs, TabSuffix, Utility } from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronUpTiny, VisaHomeTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\n\nconst subItems = ['L1 label 1', 'L1 label 2'];\n\nexport const VerticalTabWithMenu = () => {\n  const [isTabExpanded, setIsTabExpanded] = useState(false);\n\n  return (\n    <Utility vFlex vFlexWrap vGap={8}>\n      <Tabs orientation=\"vertical\" tag=\"div\">\n        <Tab tag=\"div\">\n          <Button aria-expanded={isTabExpanded} colorScheme=\"tertiary\" onClick={() => setIsTabExpanded(!isTabExpanded)}>\n            <VisaHomeTiny /> Label\n            <TabSuffix element={isTabExpanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n          </Button>\n          {isTabExpanded && (\n            <Tabs orientation=\"vertical\">\n              {subItems.map((subItem, i) => (\n                <Tab key={i}>\n                  <Button colorScheme=\"tertiary\">{subItem}</Button>\n                </Tab>\n              ))}\n            </Tabs>\n          )}\n        </Tab>\n      </Tabs>\n    </Utility>\n  );\n};\n"
          },
          "name": "Vertical tab with menu"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal tabs",
          "url": {
            "iframe": "components/tabs/default-horizontal-tabs",
            "github": "apps/workshop/src/examples/components/tabs/default-horizontal-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-horizontal-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const DefaultHorizontalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default horizontal tab"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal tabs",
          "url": {
            "iframe": "components/tabs/icon-horizontal-tabs",
            "github": "apps/workshop/src/examples/components/tabs/icon-horizontal-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\nimport { VisaStatisticsTiny, VisaTopicTiny, VisaEmailTiny, VisaHomeTiny } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-icon-horizontal-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n    icon: <VisaStatisticsTiny />,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n    icon: <VisaTopicTiny />,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    icon: <VisaEmailTiny />,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n    icon: <VisaHomeTiny />,\n  },\n];\n\nexport const IconHorizontalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.icon}\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Horizontal tab with icon"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal tabs",
          "url": {
            "iframe": "components/tabs/disabled-horizontal-tabs",
            "github": "apps/workshop/src/examples/components/tabs/disabled-horizontal-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-disabled-horizontal-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    disabled: true,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const DisabledHorizontalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              disabled={tabContent.disabled}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Horizontal tablist with disabled tab"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal tabs",
          "url": {
            "iframe": "components/tabs/horizontal-tab-with-menu",
            "github": "apps/workshop/src/examples/components/tabs/horizontal-tab-with-menu.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport { useState } from 'react';\nimport { DropdownButton, DropdownMenu, Listbox, ListboxItem, Utility, Tab, TabSuffix } from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronUpTiny, VisaHomeTiny } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-horizontal-tabs-with-menu-example';\n\nexport const HorizontalTabWithMenu = () => {\n  const [open, setOpen] = useState(false);\n\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-start',\n  });\n\n  const onClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onClick]);\n\n  return (\n    <Tab tag=\"div\" style={{ blockSize: 150 }}>\n      <DropdownButton\n        aria-controls={id}\n        aria-expanded={open}\n        colorScheme=\"tertiary\"\n        buttonSize=\"large\"\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        <VisaHomeTiny /> Label\n        {open ? <TabSuffix element={<VisaChevronUpTiny />} /> : <TabSuffix element={<VisaChevronDownTiny />} />}\n      </DropdownButton>\n      {open && (\n        <DropdownMenu\n          id={id}\n          ref={refs.setFloating}\n          style={{ maxInlineSize: '100%', inlineSize: '180px', ...floatingStyles }}\n          {...getFloatingProps()}\n        >\n          <Listbox tag=\"div\">\n            <Utility\n              element={<ListboxItem tag=\"button\" />}\n              vPaddingHorizontal={8}\n              vPaddingRight={24}\n              vPaddingVertical={11}\n            >\n              Label 1\n            </Utility>\n            <Utility\n              element={<ListboxItem tag=\"button\" />}\n              vPaddingHorizontal={8}\n              vPaddingRight={24}\n              vPaddingVertical={11}\n            >\n              Label 2\n            </Utility>\n          </Listbox>\n        </DropdownMenu>\n      )}\n    </Tab>\n  );\n};\n"
          },
          "name": "Horizontal tab with menu"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked Tabs",
          "url": {
            "iframe": "components/tabs/default-stacked-tabs",
            "github": "apps/workshop/src/examples/components/tabs/default-stacked-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\nimport { VisaStatisticsLow, VisaEmailLow, VisaReceiptLow, VisaHomeLow } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-stacked-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n    icon: <VisaHomeLow />,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n    icon: <VisaReceiptLow />,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    icon: <VisaStatisticsLow />,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n    icon: <VisaEmailLow />,\n  },\n];\n\nexport const DefaultStackedTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              stacked\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.icon}\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex]?.id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default stacked tablist"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked Tabs",
          "url": {
            "iframe": "components/tabs/disabled-stacked-tabs",
            "github": "apps/workshop/src/examples/components/tabs/disabled-stacked-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\nimport { VisaStatisticsLow, VisaEmailLow, VisaReceiptLow, VisaHomeLow } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-disabled-stacked-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n    icon: <VisaHomeLow />,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n    icon: <VisaReceiptLow />,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    icon: <VisaStatisticsLow />,\n    disabled: true,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n    icon: <VisaEmailLow />,\n  },\n];\n\nexport const DisabledStackedTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              disabled={tabContent.disabled}\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              stacked\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.icon}\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex]?.id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Stacked tablist with disabled tab"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked Tabs",
          "url": {
            "iframe": "components/tabs/stacked-tabs-with-notifications",
            "github": "apps/workshop/src/examples/components/tabs/stacked-tabs-with-notifications.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\nimport { VisaStatisticsLow, VisaEmailLow, VisaReceiptLow, VisaHomeLow } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-notifications-stacked-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n    icon: <VisaHomeLow />,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n    icon: <VisaReceiptLow />,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    icon: <VisaStatisticsLow />,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n    icon: <VisaEmailLow />,\n  },\n];\n\nexport const StackedTabsWithNotifications = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              stacked\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.icon}\n              {tabContent.tabLabel}\n              <Badge\n                tag=\"sup\"\n                aria-label={`${index + 1} unread notification${index === 0 ? '' : 's'}`}\n                badgeVariant=\"number\"\n              >\n                {index + 1}\n              </Badge>\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex]?.id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Stacked tabs with notifications"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tabs",
          "url": {
            "iframe": "components/tabs/alternate-horizontal-tabs",
            "github": "apps/workshop/src/examples/components/tabs/alternate-horizontal-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-alternate-horizontal-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const AlternateHorizontalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Surface surfaceType=\"alternate\">\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"xxlarge\">\n        {/*\n          We have a nested surface that has been styled in our app's stylesheet. \n          This has been done to leverage darker palette variables and bring contrast to this custom tabpanel.\n\n          The CSS rule is something like this:\n\n          .v-surface.v-alternate .v-surface {\n            // The background color is set to surface-3 of the default palette.\n            background: var(--palette-default-surface-3);\n          }\n        */}\n        <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Surface>\n  );\n};\n"
          },
          "name": "Alternate horizontal tablist"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tabs",
          "url": {
            "iframe": "components/tabs/alternate-vertical-tabs",
            "github": "apps/workshop/src/examples/components/tabs/alternate-vertical-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-alternate-vertical-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const AlternateVerticalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'vertical', defaultSelected: 0 });\n\n  return (\n    <Surface surfaceType=\"alternate\">\n      <Utility vFlex vFlexWrap vGap={8}>\n        <Tabs orientation=\"vertical\" onKeyDown={onKeyNavigation} role=\"tablist\" style={{ flexBasis: '30%' }}>\n          {tabsContent.map((tabContent, index) => (\n            <Tab key={tabContent.id} role=\"none\">\n              <Button\n                aria-selected={index === selectedIndex}\n                aria-controls={tabContent.id}\n                colorScheme=\"tertiary\"\n                onClick={() => onIndexChange(index)}\n                ref={el => {\n                  tabsRef.current[index] = el;\n                }}\n                role=\"tab\"\n                tabIndex={getTabIndex(index)}\n              >\n                {tabContent.tabLabel}\n              </Button>\n            </Tab>\n          ))}\n        </Tabs>\n        <Utility vFlex vFlexGrow vElevation=\"xxlarge\">\n          {/*\n          We have a nested surface that has been styled in our app's stylesheet. \n          This has been done to leverage darker palette variables and bring contrast to this custom tabpanel.\n\n          The CSS rule is something like this:\n\n          .v-surface.v-alternate .v-surface {\n            // The background color is set to surface-3 of the default palette.\n            background: var(--palette-default-surface-3);\n          }\n        */}\n          <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n            <span>{tabsContent[selectedIndex]?.text}</span>\n          </Surface>\n        </Utility>\n      </Utility>\n    </Surface>\n  );\n};\n"
          },
          "name": "Alternate vertical tablist"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tabs",
          "url": {
            "iframe": "components/tabs/alternate-stacked-tabs",
            "github": "apps/workshop/src/examples/components/tabs/alternate-stacked-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\nimport { VisaStatisticsLow, VisaEmailLow, VisaReceiptLow, VisaHomeLow } from '@visa/nova-icons-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-alternate-stacked-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n    icon: <VisaHomeLow />,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n    icon: <VisaReceiptLow />,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n    icon: <VisaStatisticsLow />,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n    icon: <VisaEmailLow />,\n  },\n];\n\nexport const AlternateStackedTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Surface surfaceType=\"alternate\">\n      <Utility>\n        <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n          {tabsContent.map((tabContent, index) => (\n            <Tab key={`default-stacked-tab-${index}`} role=\"none\">\n              <Button\n                aria-selected={index === selectedIndex}\n                aria-controls={tabContent.id}\n                colorScheme=\"tertiary\"\n                onClick={() => onIndexChange(index)}\n                ref={el => {\n                  tabsRef.current[index] = el;\n                }}\n                role=\"tab\"\n                stacked\n                tabIndex={getTabIndex(index)}\n              >\n                {tabContent.icon}\n                {tabContent.tabLabel}\n              </Button>\n            </Tab>\n          ))}\n        </Tabs>\n        <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"xxlarge\">\n          {/*\n          We have a nested surface that has been styled in our app's stylesheet. \n          This has been done to leverage darker palette variables and bring contrast to this custom tabpanel.\n\n          The CSS rule is something like this:\n\n          .v-surface.v-alternate .v-surface {\n            // The background color is set to surface-3 of the default palette.\n            background: var(--palette-default-surface-3);\n          }\n        */}\n          <Surface id={tabsContent[selectedIndex]?.id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n            <span>{tabsContent[selectedIndex]?.text}</span>\n          </Surface>\n        </Utility>\n      </Utility>\n    </Surface>\n  );\n};\n"
          },
          "name": "Alternate stacked tablist"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tabs",
          "url": {
            "iframe": "components/tabs/auto-horizontal-tabs",
            "github": "apps/workshop/src/examples/components/tabs/auto-horizontal-tabs.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Surface, Tab, Tabs, Utility, useTabs } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'nova-auto-horizontal-tabs-example';\n\nconst tabsContent = [\n  {\n    tabLabel: 'Label 1',\n    text: `This is the content area for label 1`,\n    id: `${id}-tab-0`,\n  },\n  {\n    tabLabel: 'Label 2',\n    text: `This is the content area for label 2`,\n    id: `${id}-tab-1`,\n  },\n  {\n    tabLabel: 'Label 3',\n    text: `This is the content area for label 3`,\n    id: `${id}-tab-2`,\n  },\n  {\n    tabLabel: 'Label 4',\n    text: `This is the content area for label 4`,\n    id: `${id}-tab-3`,\n  },\n];\n\nexport const AutoHorizontalTabs = () => {\n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({ autoSelect: true, arrowKeyNavigation: 'horizontal', defaultSelected: 0 });\n\n  return (\n    <Utility>\n      <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n        {tabsContent.map((tabContent, index) => (\n          <Tab key={tabContent.id} role=\"none\">\n            <Button\n              aria-selected={index === selectedIndex}\n              aria-controls={tabContent.id}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              tabIndex={getTabIndex(index)}\n            >\n              {tabContent.tabLabel}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      <Utility vMarginVertical={8} vFlex vFlexGrow vElevation=\"inset\">\n        <Surface id={tabsContent[selectedIndex].id} role=\"tabpanel\" style={{ minBlockSize: '200px' }}>\n          <span>{tabsContent[selectedIndex]?.text}</span>\n        </Surface>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Tablist with automatic activation"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tabs",
          "url": {
            "iframe": "components/tabs/reusable",
            "github": "apps/workshop/src/examples/components/tabs/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import { VisaDeleteTiny, VisaExportTiny, VisaFileDownloadTiny, VisaFileUploadTiny } from '@visa/nova-icons-react';\nimport {\n  Badge,\n  Button,\n  Surface,\n  Tab,\n  Tabs,\n  useTabs,\n  Utility,\n  type ButtonProperties,\n  type TabsProperties,\n} from '@visa/nova-react';\nimport { useId, useState, type FormEvent, type ReactNode } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\n \nexport type NovaTabsOption = Omit<ButtonProperties<'button'>, 'children'> & {\n  content?: ReactNode;\n  label?: ReactNode;\n  notifications?: number;\n  prefix?: ReactNode;\n  selected?: boolean;\n  suffix?: ReactNode;\n};\n \n// Nova Tabs Component Props\nexport type NovaTabsProps = TabsProperties<'ul'> & {\n  alternate?: boolean;\n  autoSelect?: boolean;\n  childSurface?: boolean;\n  defaultSelectedIndex?: number;\n  onSelectedIndexChange?: (index: number) => void;\n  selectedIndex?: number;\n  stacked?: boolean;\n  tabs?: NovaTabsOption[];\n};\n \n// Main Nova Tabs Component\nexport const NovaTabs = ({\n  alternate = false,\n  autoSelect = true,\n  children,\n  childSurface = true,\n  defaultSelectedIndex = 0,\n  id: idProp,\n  onSelectedIndexChange,\n  orientation = 'vertical',\n  selectedIndex: selectedIndexProp,\n  stacked = false,\n  tabs = [],\n  ...remainingProps\n}: NovaTabsProps) => {\n  const generatedId = useId();\n  const id = idProp ?? generatedId;\n \n  const {\n    getTabIndex,\n    onIndexChange,\n    onKeyNavigation,\n    ref: tabsRef,\n    selectedIndex,\n  } = useTabs({\n    arrowKeyNavigation: orientation,\n    autoSelect,\n    defaultSelected: defaultSelectedIndex,\n    selectedIndex: selectedIndexProp,\n    onSelectedIndexChange,\n  });\n \n  const vertical = orientation === 'vertical';\n \n  const tabContent = childSurface ? (\n    <Utility vMarginVertical={vertical ? undefined : 8} vFlex vFlexGrow vElevation=\"inset\">\n      {/*\n          We have a nested surface that has been styled in our app's stylesheet.\n          This has been done to leverage darker palette variables and bring contrast to this custom tabpanel.\n \n          The CSS rule is something like this:\n \n          .v-surface.v-alternate .v-surface {\n            // The background color is set to surface-3 of the default palette.\n            background: var(--palette-default-surface-3);\n          }\n        */}\n      <Surface id={`${id}-tab-${selectedIndex}`} role=\"tabpanel\">\n        {tabs[selectedIndex]?.content}\n        {children}\n      </Surface>\n    </Utility>\n  ) : (\n    <div id={`${id}-tab-${selectedIndex}`} role=\"tabpanel\">\n      {tabs[selectedIndex]?.content}\n      {children}\n    </div>\n  );\n \n  const content = (\n    <Utility vFlex={vertical} vFlexRow={vertical} vFlexWrap vGap={8}>\n      <Tabs\n        onKeyDown={onKeyNavigation}\n        orientation={orientation}\n        role=\"tablist\"\n        style={{ inlineSize: 'max-content' }}\n        {...remainingProps}\n      >\n        {tabs.map(({ id, label, notifications, prefix, suffix, ...remainingButtonProps }, index) => (\n          <Tab key={`${id}-tab-${index}`} role=\"none\">\n            <Button\n              aria-controls={`${id}-tab-${index}`}\n              aria-selected={index === selectedIndex}\n              colorScheme=\"tertiary\"\n              onClick={() => onIndexChange(index)}\n              ref={el => {\n                tabsRef.current[index] = el;\n              }}\n              role=\"tab\"\n              stacked={stacked}\n              tabIndex={getTabIndex(index)}\n              {...(remainingButtonProps as ButtonProperties)}\n            >\n              {prefix}\n              {label}\n              {suffix}\n              {notifications !== undefined && notifications > 0 && (\n                <Badge\n                  aria-label={`${notifications} unread notification${notifications > 1 ? 's' : ''}`}\n                  badgeVariant=\"number\"\n                  tag=\"sup\"\n                >\n                  {notifications}\n                </Badge>\n              )}\n            </Button>\n          </Tab>\n        ))}\n      </Tabs>\n      {tabContent}\n    </Utility>\n  );\n \n  return alternate ? <Surface surfaceType=\"alternate\">{content}</Surface> : content;\n};\n \n// export default NovaTabs;\n \n/** !!! DELETE ME START !!! */\n \nconst demoTabs: NovaTabsOption[] = [\n  { content: 'This is the content area for label 1', label: 'Label 1' },\n  { content: 'This is the content area for label 2', label: 'Label 2', disabled: true },\n  { content: 'This is the content area for label 3', label: 'Label 3', notifications: 0 },\n  { content: 'This is the content area for label 4', label: 'Label 4' },\n];\n \n// These are separate from the main tabs because these can't be customized inside of a textarea input.\nconst demoTabsIcons: ReactNode[] = [\n  // eslint-disable-next-line react/jsx-key\n  <VisaExportTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaFileDownloadTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaFileUploadTiny />,\n  // eslint-disable-next-line react/jsx-key\n  <VisaDeleteTiny />,\n];\n \nconst orientations: { label: string; value: TabsProperties['orientation'] }[] = [\n  { label: 'Horizontal', value: 'horizontal' },\n  { label: 'Vertical', value: 'vertical' },\n];\n \n// Demo Component Types\ninterface DemoCustomizations {\n  alternate: boolean;\n  autoSelect: boolean;\n  childSurface: boolean;\n  orientation: TabsProperties['orientation'];\n  selectedIndex: number;\n  showPrefixIcons: boolean;\n  showSuffixIcons: boolean;\n  stacked: boolean;\n  tabs: string;\n}\n \nconst defaultCustomizations: DemoCustomizations = {\n  alternate: false,\n  autoSelect: true,\n  childSurface: true,\n  orientation: 'horizontal',\n  selectedIndex: 0,\n  showPrefixIcons: true,\n  showSuffixIcons: false,\n  stacked: false,\n  tabs: JSON.stringify(demoTabs, null, 4),\n};\n \n// Demo Component\nexport const NovaTabsDemo = () => {\n  const [customizations, setCustomizations] = useState<Omit<DemoCustomizations, 'tabs'> & { tabs: NovaTabsOption[] }>({\n    ...defaultCustomizations,\n    tabs: demoTabs,\n  });\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n \n  const handleInputChange = <T = string | boolean,>(field: keyof DemoCustomizations, value: T) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    try {\n      const parsedOptions = JSON.parse(formValues.tabs || '[]') as NovaTabsOption[];\n      setCustomizations({\n        ...formValues,\n        tabs: parsedOptions,\n      });\n    } catch (error) {\n      console.error('Invalid JSON for tabs:', error);\n    }\n  };\n \n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations({\n      ...defaultCustomizations,\n      tabs: demoTabs,\n    });\n  };\n \n  const tabsWithCustomizations = customizations.tabs.map((option, index) => {\n    const prefix = customizations.showPrefixIcons ? demoTabsIcons[index % demoTabsIcons.length] : undefined;\n    const suffix = customizations.showSuffixIcons ? demoTabsIcons[index % demoTabsIcons.length] : undefined;\n    return { ...option, prefix, suffix } as NovaTabsOption;\n  });\n \n  return (\n    <div>\n      <NovaTabs\n        alternate={customizations.alternate}\n        autoSelect={customizations.autoSelect}\n        childSurface={customizations.childSurface}\n        onSelectedIndexChange={index => setCustomizations(prev => ({ ...prev, selectedIndex: index }))}\n        orientation={customizations.orientation}\n        selectedIndex={customizations.selectedIndex}\n        stacked={customizations.stacked}\n        tabs={tabsWithCustomizations || []}\n      />\n \n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                blockSize=\"100px\"\n                label=\"Tabs (JSON)\"\n                onChange={e => handleInputChange('tabs', e.target.value)}\n                resizable\n                textarea\n                value={formValues.tabs}\n              />\n \n              <NovaSelect\n                label=\"Orientation\"\n                onChange={e =>\n                  handleInputChange('orientation', e.target.value as NonNullable<DemoCustomizations['orientation']>)\n                }\n                options={orientations}\n                value={formValues.orientation}\n              />\n \n              <NovaInput\n                clearable\n                label=\"Selected index\"\n                onChange={e => handleInputChange('selectedIndex', +e.target.value)}\n                placeholder=\"0\"\n                type=\"number\"\n                value={formValues.selectedIndex}\n              />\n \n              <NovaCheckbox\n                checked={formValues.alternate}\n                label=\"Alternate\"\n                onChange={e => handleInputChange('alternate', e.target.checked)}\n              />\n \n              <NovaCheckbox\n                checked={formValues.autoSelect}\n                label=\"Auto select tab with keyboard focus\"\n                onChange={e => handleInputChange('autoSelect', e.target.checked)}\n              />\n \n              <NovaCheckbox\n                checked={formValues.childSurface}\n                label=\"Child surface\"\n                onChange={e => handleInputChange('childSurface', e.target.checked)}\n              />\n \n              <NovaCheckbox\n                checked={formValues.showPrefixIcons}\n                label=\"Show prefix icons\"\n                onChange={e => handleInputChange('showPrefixIcons', e.target.checked)}\n              />\n \n              <NovaCheckbox\n                checked={formValues.showSuffixIcons}\n                label=\"Show suffix icons\"\n                onChange={e => handleInputChange('showSuffixIcons', e.target.checked)}\n              />\n \n              <NovaCheckbox\n                checked={formValues.stacked}\n                label=\"Stacked\"\n                onChange={e => handleInputChange('stacked', e.target.checked)}\n              />\n            </Utility>\n \n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaTabsDemo;\n/** !!! DELETE ME END !!! */"
          },
          "name": "Reusable tablist"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Tabs",
          "selector": "<Tabs />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Organizational element that separates content and allows users to switch between views."
        },
        {
          "order": 2,
          "name": "Tab",
          "selector": "<Tab />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Singular tab component to be used in a tab group."
        },
        {
          "order": 3,
          "name": "Tabsuffix",
          "selector": "<TabSuffix />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Utility class for positioning and styling elements at the end of tab components."
        },
        {
          "order": 4,
          "name": "useTabs",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook allows us to set the <defaultSelected> value, which indicates that we are selecting that item by default."
        }
      ],
      "properties": [
        {
          "name": "orientation",
          "section": "Tabs",
          "data": {
            "name": "orientation",
            "type": "\"horizontal\" , \"vertical\"",
            "default": "horizontal",
            "required": "false",
            "description": "Orientation"
          }
        },
        {
          "name": "stacked",
          "section": "Tabs",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked"
          }
        },
        {
          "name": "tag",
          "section": "Tabs",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "ul",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "sectionTitle",
          "section": "Tab",
          "data": {
            "name": "sectionTitle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "section title"
          }
        },
        {
          "name": "tag",
          "section": "Tab",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "li",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "children",
          "section": "Tabsuffix",
          "data": {
            "name": "children",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Child element that the styles are applies to. Only allows for single child element. (not compatible with element property)"
          }
        },
        {
          "name": "element",
          "section": "Tabsuffix",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with children)"
          }
        }
      ]
    },
    {
      "name": "toggle",
      "version": "0.0.1",
      "description": "Selection element that allows users to switch between states or views.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Single-select toggle buttons",
          "description": "",
          "order": 1
        },
        {
          "name": "Multi-select toggle buttons",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom toggle buttons",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/default-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/default-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-toggle';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, defaultSelected: true },\n  { label: 'Label 2', id: `${id}-label-2` },\n  { label: 'Label 3', id: `${id}-label-3` },\n];\n\nexport const DefaultToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle\n            tag=\"button\"\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n          >\n            {option.label}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Single-select toggles"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/leading-icon-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/leading-icon-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationTiny, VisaViewGridTiny, VisaViewListTiny } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'leading-icon-toggle';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, icon: <VisaMapLocationTiny />, defaultSelected: true },\n  { label: 'Label 2', id: `${id}-label-2`, icon: <VisaViewListTiny /> },\n  { label: 'Label 3', id: `${id}-label-3`, icon: <VisaViewGridTiny /> },\n];\n\nexport const LeadingIconToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle\n            tag=\"button\"\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n          >\n            {option.icon}\n            {option.label}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Single-select toggles with leading icon"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/trailing-icon-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/trailing-icon-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationTiny, VisaViewGridTiny, VisaViewListTiny } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'trailing-icon-toggles';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, icon: <VisaMapLocationTiny />, defaultSelected: true },\n  { label: 'Label 2', id: `${id}-label-2`, icon: <VisaViewListTiny /> },\n  { label: 'Label 3', id: `${id}-label-3`, icon: <VisaViewGridTiny /> },\n];\n\nexport const TrailingIconToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle\n            tag=\"button\"\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n          >\n            {option.label}\n            {option.icon}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Single-select toggles with trailing icon"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/icon-only-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/icon-only-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationTiny, VisaViewGridTiny, VisaViewListTiny } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'icon-only-toggles';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, icon: <VisaMapLocationTiny />, defaultSelected: true },\n  { label: 'Label 2', id: `${id}-label-2`, icon: <VisaViewListTiny /> },\n  { label: 'Label 3', id: `${id}-label-3`, icon: <VisaViewGridTiny /> },\n];\n\nexport const IconOnlyToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle\n            tag=\"button\"\n            aria-label={option.label}\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n          >\n            {option.icon}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Single-select toggles with icon only"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/disabled-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/disabled-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationTiny, VisaViewGridTiny, VisaViewListTiny } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-toggles';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, icon: <VisaMapLocationTiny />, disabled: true },\n  { label: 'Label 2', id: `${id}-label-2`, icon: <VisaViewListTiny />, disabled: true },\n  { label: 'Label 3', id: `${id}-label-3`, icon: <VisaViewGridTiny />, disabled: true },\n];\n\nexport const DisabledToggles = () => {\n  return (\n    <ToggleContainer>\n      {options.map(option => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle<'button'> tag=\"button\" disabled={option.disabled}>\n            {option.icon}\n            {option.label}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Disabled toggles"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Single-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/disabled-and-active-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/disabled-and-active-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationTiny, VisaViewGridTiny, VisaViewListTiny } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'disabled-and-active-toggles';\n\nconst options = [\n  { label: 'Label 1', id: `${id}-label-1`, icon: <VisaMapLocationTiny />, disabled: false, defaultSelected: true },\n  { label: 'Label 2', id: `${id}-label-2`, icon: <VisaViewListTiny />, disabled: false },\n  { label: 'Label 3', id: `${id}-label-3`, icon: <VisaViewGridTiny />, disabled: true },\n];\n\nexport const DisabledAndActiveToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle<'button'>\n            tag=\"button\"\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n            disabled={option.disabled}\n          >\n            {option.icon}\n            {option.label}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Disabled and active toggles"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/multi-select-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/multi-select-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationLow, VisaViewGridLow, VisaViewListLow } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-select-toggles';\n\nconst options = [\n  { id: `${id}-label-1`, label: 'Label 1', icon: <VisaMapLocationLow />, defaultSelected: true },\n  { id: `${id}-label-2`, label: 'Label 2', icon: <VisaViewListLow /> },\n  { id: `${id}-label-3`, label: 'Label 3', icon: <VisaViewGridLow />, defaultSelected: true },\n];\n\nexport const MultiSelectToggles = () => {\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(prevState => {\n      return prevState.map((buttonSelected, buttonIndex) =>\n        pressedIndex === buttonIndex ? !buttonSelected : buttonSelected\n      );\n    });\n  };\n\n  return (\n    <ToggleContainer>\n      {options.map((option, optionIndex) => (\n        <UtilityFragment key={option.id} vGap={6}>\n          <Toggle\n            tag=\"button\"\n            aria-label={option.label}\n            aria-pressed={togglePressedState[optionIndex]}\n            onClick={() => handleSingleSelectTogglePress(optionIndex)}\n          >\n            {option.icon}\n          </Toggle>\n        </UtilityFragment>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Multi-select toggles"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select toggle buttons",
          "url": {
            "iframe": "components/toggle-button/standalone-multi-select-toggle",
            "github": "apps/workshop/src/examples/components/toggle-button/standalone-multi-select-toggle.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationLow } from '@visa/nova-icons-react';\nimport { Toggle, ToggleContainer, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'standalone-multi-select-toggle';\n\nexport const StandaloneMultiSelectToggle = () => {\n  const [togglePressedState, setTogglePressedState] = useState<boolean>(false);\n\n  const handleTogglePress = () => {\n    setTogglePressedState(prevState => !prevState);\n  };\n\n  return (\n    <ToggleContainer>\n      <UtilityFragment vGap={6}>\n        <Toggle id={id} tag=\"button\" aria-label=\"Label 1\" aria-pressed={togglePressedState} onClick={handleTogglePress}>\n          <VisaMapLocationLow />\n        </Toggle>\n      </UtilityFragment>\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Standalone multi-select toggle"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Custom toggle buttons",
          "url": {
            "iframe": "components/toggle-button/single-select-radio-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/single-select-radio-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Radio, Toggle, ToggleContainer } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'single-select-radio-toggles';\n\nconst options = [\n  { id: `${id}-label-1`, label: 'Label 1', defaultSelected: true },\n  { id: `${id}-label-2`, label: 'Label 2' },\n  { id: `${id}-label-3`, label: 'Label 3' },\n];\n\nexport const SingleSelectRadioToggles = () => {\n  return (\n    <ToggleContainer>\n      {options.map((option, index) => (\n        <Toggle className=\"v-gap-6\" htmlFor={option.id} key={`${id}-option-${index}`}>\n          <Radio defaultChecked={option.defaultSelected} id={option.id} name={`${id}-options`} />\n          {option.label}\n        </Toggle>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Single-select toggles using radio buttons"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Custom toggle buttons",
          "url": {
            "iframe": "components/toggle-button/multi-select-checkbox-toggles",
            "github": "apps/workshop/src/examples/components/toggle-button/multi-select-checkbox-toggles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMapLocationLow, VisaViewGridLow, VisaViewListLow } from '@visa/nova-icons-react';\nimport { Checkbox, Toggle, ToggleContainer } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'multi-select-checkbox-toggle';\n\nconst options = [\n  { id: `${id}-label-1`, label: 'Label 1', icon: <VisaMapLocationLow />, checked: true },\n  { id: `${id}-label-2`, label: 'Label 2', icon: <VisaViewListLow />, checked: false },\n  { id: `${id}-label-3`, label: 'Label 3', icon: <VisaViewGridLow />, checked: true },\n];\n\nexport const MultiSelectCheckboxToggles = () => {\n  return (\n    <ToggleContainer>\n      {options.map(({ label, icon, checked }, index) => (\n        <Toggle className=\"v-gap-6\" aria-label={label} htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`}>\n          <Checkbox defaultChecked={checked} id={`${id}-option-${index}`} name={`${id}-options`} /> {icon}\n        </Toggle>\n      ))}\n    </ToggleContainer>\n  );\n};\n"
          },
          "name": "Multi-select toggles using checkboxes"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Toggle",
          "selector": "<Toggle />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Selection element that allows users to switch between states or views."
        },
        {
          "order": 2,
          "name": "Togglecontainer",
          "selector": "<ToggleContainer />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Element to contain a group of toggle components."
        }
      ],
      "properties": [
        {
          "name": "iconOnly",
          "section": "Toggle",
          "data": {
            "name": "iconOnly",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icons only toggle button"
          }
        },
        {
          "name": "tag",
          "section": "Toggle",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "label",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "tag",
          "section": "Togglecontainer",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "fieldset",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "tooltip",
      "version": "0.0.1",
      "description": "Short message communicating the function or context of a control or object.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default tooltips",
          "description": "",
          "order": 1
        },
        {
          "name": "Custom tooltips",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default tooltips",
          "url": {
            "iframe": "components/tooltip/top-tooltip",
            "github": "apps/workshop/src/examples/components/tooltip/top-tooltip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n} from '@floating-ui/react';\nimport { Button, Tooltip, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const TopTooltip = () => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(2)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement: 'top',\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vMargin={24}>\n      <Button ref={refs.setReference} {...getReferenceProps()}>\n        Primary action\n      </Button>\n      {isOpen && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            left: x,\n            position: strategy,\n            top: y,\n            width: 'fit-content',\n          }}\n          {...getFloatingProps()}\n        >\n          This is a tooltip\n        </Tooltip>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Top-positioned tooltip"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default tooltips",
          "url": {
            "iframe": "components/tooltip/bottom-tooltip",
            "github": "apps/workshop/src/examples/components/tooltip/bottom-tooltip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n} from '@floating-ui/react';\nimport { Button, Tooltip, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const BottomTooltip = () => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(2)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement: 'bottom',\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vMargin={24}>\n      <Button ref={refs.setReference} {...getReferenceProps()}>\n        Primary action\n      </Button>\n      {isOpen && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            left: x,\n            position: strategy,\n            top: y,\n            width: 'fit-content',\n          }}\n          {...getFloatingProps()}\n        >\n          This is a tooltip\n        </Tooltip>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Bottom-positioned tooltip"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default tooltips",
          "url": {
            "iframe": "components/tooltip/left-tooltip",
            "github": "apps/workshop/src/examples/components/tooltip/left-tooltip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n} from '@floating-ui/react';\nimport { Button, Tooltip, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const LeftTooltip = () => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(2)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement: 'left',\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vMargin={24}>\n      <Button ref={refs.setReference} {...getReferenceProps()}>\n        Primary action\n      </Button>\n      {isOpen && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            left: x,\n            position: strategy,\n            top: y,\n            width: 'fit-content',\n          }}\n          {...getFloatingProps()}\n        >\n          This is a tooltip\n        </Tooltip>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Left-positioned tooltip"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default tooltips",
          "url": {
            "iframe": "components/tooltip/right-tooltip",
            "github": "apps/workshop/src/examples/components/tooltip/right-tooltip.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n} from '@floating-ui/react';\nimport { Button, Tooltip, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const RightTooltip = () => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(2)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement: 'right',\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vMargin={24}>\n      <Button ref={refs.setReference} {...getReferenceProps()}>\n        Primary action\n      </Button>\n      {isOpen && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            left: x,\n            position: strategy,\n            top: y,\n            width: 'fit-content',\n          }}\n          {...getFloatingProps()}\n        >\n          This is a tooltip\n        </Tooltip>\n      )}\n    </Utility>\n  );\n};\n"
          },
          "name": "Right-positioned tooltip"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Custom tooltips",
          "url": {
            "iframe": "components/tooltip/reusable",
            "github": "apps/workshop/src/examples/components/tooltip/reusable.tsx"
          },
          "tags": [
            "custom",
            "AI-first"
          ],
          "snippets": {
            "tsx": "import {\n  offset,\n  safePolygon,\n  useDismiss,\n  useFloating,\n  useFocus,\n  useHover,\n  useInteractions,\n  useRole,\n  type Placement,\n} from '@floating-ui/react';\nimport { VisaInformationLow } from '@visa/nova-icons-react';\nimport { Button, Link, Tooltip, Utility, type ButtonProperties } from '@visa/nova-react';\nimport { cloneElement, isValidElement, useState, type ReactElement, type ReactNode } from 'react';\nimport { NovaAccordion } from '../accordion/reusable';\nimport { NovaInput } from '../input/reusable';\nimport { NovaSelect } from '../select/reusable';\nimport { NovaCheckbox } from '../checkbox/reusable';\n\n// Props passed to the trigger element\nexport type TooltipTriggerProps = {\n  ref: (node: HTMLElement | null) => void;\n} & Record<string, unknown>;\n\n// Nova Tooltip Component Props\nexport type NovaTooltipProps = Omit<ButtonProperties<'button'>, 'children'> & {\n  /** Render function, ReactElement, or string. Render function receives ref and interaction props. */\n  children?: ReactNode;\n  element?: ReactElement | ((props: TooltipTriggerProps) => ReactNode);\n  maxWidth?: CSSStyleDeclaration['maxWidth'];\n  offset?: number;\n  placement?: Placement;\n  tooltip?: ReactNode;\n};\n\n// Main Nova Tooltip Component\nexport const NovaTooltip = ({\n  children = <VisaInformationLow aria-label=\"More information\" />,\n  element,\n  maxWidth = 'unset',\n  offset: offsetValue = 2,\n  placement = 'top',\n  tooltip,\n  ...remainingProps\n}: NovaTooltipProps) => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { x, y, strategy, refs, context } = useFloating({\n    middleware: [offset(offsetValue)],\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    placement,\n  });\n\n  const dismiss = useDismiss(context);\n  const focus = useFocus(context);\n  const hover = useHover(context, { handleClose: safePolygon(), move: false });\n  const role = useRole(context, { role: 'tooltip' });\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, focus, hover, role]);\n\n  // Props to pass to the trigger element\n  const triggerProps: TooltipTriggerProps = {\n    ref: refs.setReference,\n    ...getReferenceProps(),\n  };\n\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vMargin={24}>\n      {element && (\n        <>\n          {typeof element === 'function' && element(triggerProps)}\n          {isValidElement(element) && cloneElement(element, triggerProps)}\n        </>\n      )}\n\n      {!element && (\n        <Button\n          buttonSize=\"small\"\n          iconButton\n          colorScheme=\"tertiary\"\n          {...(remainingProps as ButtonProperties)}\n          {...triggerProps}\n        >\n          {children}\n        </Button>\n      )}\n\n      {isOpen && tooltip && (\n        <Tooltip\n          ref={refs.setFloating}\n          style={{\n            inlineSize: 'fit-content',\n            left: x,\n            maxInlineSize: maxWidth,\n            position: strategy,\n            top: y,\n          }}\n          {...getFloatingProps()}\n        >\n          {tooltip}\n        </Tooltip>\n      )}\n    </Utility>\n  );\n};\n\n// export default NovaTooltip;\n\n/** !!! DELETE ME START !!! */\n\n// Demo Component Types\ninterface DemoCustomizations {\n  asLink: boolean;\n  buttonSize: ButtonProperties['buttonSize'];\n  colorScheme: ButtonProperties['colorScheme'];\n  iconButton: boolean;\n  label: string;\n  maxWidth: string;\n  offset: number;\n  placement: Placement;\n  tooltip: string;\n}\n\nconst buttonColors: { label: string; value: ButtonProperties['colorScheme'] }[] = [\n  { label: 'Primary', value: 'primary' },\n  { label: 'Secondary', value: 'secondary' },\n  { label: 'Tertiary', value: 'tertiary' },\n];\n\nconst buttonSizes: { label: string; value: ButtonProperties['buttonSize'] }[] = [\n  { label: 'Small', value: 'small' },\n  { label: 'Medium', value: 'medium' },\n  { label: 'Large', value: 'large' },\n];\n\nconst placements: { label: string; value: Placement }[] = [\n  { label: 'Bottom', value: 'bottom' },\n  { label: 'Bottom end', value: 'bottom-end' },\n  { label: 'Bottom start', value: 'bottom-start' },\n  { label: 'Left', value: 'left' },\n  { label: 'Left end', value: 'left-end' },\n  { label: 'Left start', value: 'left-start' },\n  { label: 'Right', value: 'right' },\n  { label: 'Right end', value: 'right-end' },\n  { label: 'Right start', value: 'right-start' },\n  { label: 'Top', value: 'top' },\n  { label: 'Top start', value: 'top-start' },\n  { label: 'Top end', value: 'top-end' },\n];\n\nconst defaultCustomizations: DemoCustomizations = {\n  asLink: false,\n  buttonSize: 'medium',\n  colorScheme: 'primary',\n  iconButton: false,\n  label: 'Primary action',\n  maxWidth: 'unset',\n  offset: 2,\n  placement: 'top',\n  tooltip: 'This is a tooltip',\n};\n\n// Demo Component\nexport const NovaTooltipDemo = () => {\n  const [customizations, setCustomizations] = useState<DemoCustomizations>(defaultCustomizations);\n  const [formValues, setFormValues] = useState<DemoCustomizations>(defaultCustomizations);\n\n  const handleInputChange = (field: keyof DemoCustomizations, value: string | boolean) => {\n    setFormValues(prev => ({\n      ...prev,\n      [field]: value,\n    }));\n  };\n\n  const handleApply = (e: React.FormEvent) => {\n    e.preventDefault();\n    setCustomizations(formValues);\n  };\n\n  const handleReset = () => {\n    setFormValues(defaultCustomizations);\n    setCustomizations(defaultCustomizations);\n  };\n\n  const handleClick = () => {\n    console.log('Tooltip button clicked');\n  };\n\n  return (\n    <div>\n      <NovaTooltip\n        buttonSize={customizations.asLink ? undefined : customizations.buttonSize || undefined}\n        colorScheme={customizations.asLink ? undefined : customizations.colorScheme || undefined}\n        element={customizations.asLink ? <Link>{customizations.label || 'Tooltip link'}</Link> : undefined}\n        iconButton={customizations.asLink ? undefined : customizations.iconButton || undefined}\n        onClick={handleClick}\n        tooltip={customizations.tooltip || ''}\n        offset={+customizations.offset}\n        placement={customizations.placement || 'top'}\n        maxWidth={customizations.maxWidth || 'unset'}\n      >\n        {customizations.iconButton ? (\n          <VisaInformationLow aria-label={customizations.label} />\n        ) : (\n          customizations.label || ''\n        )}\n      </NovaTooltip>\n\n      <div style={{ marginTop: '24px' }}>\n        <NovaAccordion title=\"Customize demo\">\n          <form onSubmit={handleApply}>\n            <Utility vFlex vFlexCol vGap={16} style={{ marginBottom: '32px' }}>\n              <NovaInput\n                clearable\n                label=\"Label\"\n                onChange={e => handleInputChange('label', e.target.value)}\n                placeholder=\"Primary action\"\n                value={formValues.label}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Tooltip\"\n                onChange={e => handleInputChange('tooltip', e.target.value)}\n                placeholder=\"This is a really really really long tooltip\"\n                value={formValues.tooltip}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Max width\"\n                onChange={e => handleInputChange('maxWidth', e.target.value)}\n                placeholder=\"100px\"\n                value={formValues.maxWidth}\n              />\n\n              <NovaInput\n                clearable\n                label=\"Offset\"\n                onChange={e => handleInputChange('offset', e.target.value)}\n                placeholder=\"2\"\n                type=\"number\"\n                value={formValues.offset}\n              />\n\n              {!formValues.asLink && (\n                <NovaSelect\n                  label=\"Button color scheme\"\n                  onChange={e =>\n                    handleInputChange('colorScheme', e.target.value as NonNullable<DemoCustomizations['colorScheme']>)\n                  }\n                  options={buttonColors}\n                  value={formValues.colorScheme}\n                />\n              )}\n\n              {!formValues.asLink && (\n                <NovaSelect\n                  label=\"Button size\"\n                  onChange={e =>\n                    handleInputChange('buttonSize', e.target.value as NonNullable<DemoCustomizations['buttonSize']>)\n                  }\n                  options={buttonSizes}\n                  value={formValues.buttonSize}\n                />\n              )}\n\n              <NovaSelect\n                label=\"Placement\"\n                onChange={e => handleInputChange('placement', e.target.value as DemoCustomizations['placement'])}\n                options={placements}\n                value={formValues.placement}\n              />\n\n              {!formValues.asLink && (\n                <NovaCheckbox\n                  checked={formValues.iconButton}\n                  label=\"Icon button\"\n                  description=\"It is recommended to use the small button size and tertiary color scheme with this option.\"\n                  onChange={e => handleInputChange('iconButton', e.target.checked)}\n                />\n              )}\n\n              <NovaCheckbox\n                checked={formValues.asLink}\n                label=\"Show as link\"\n                onChange={e => handleInputChange('asLink', e.target.checked)}\n              />\n            </Utility>\n\n            <Utility vFlex vGap={16} style={{ marginBottom: '16px' }}>\n              <Button type=\"submit\">Apply</Button>\n              <Button colorScheme=\"secondary\" type=\"button\" onClick={handleReset}>\n                Reset\n              </Button>\n            </Utility>\n          </form>\n        </NovaAccordion>\n      </div>\n    </div>\n  );\n};\nexport default NovaTooltipDemo;\n/** !!! DELETE ME END !!! */\n"
          },
          "name": "Reusable tooltip"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Tooltip",
          "selector": "<Tooltip />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Short message communicating the function or context of a control or object."
        }
      ],
      "properties": [
        {
          "name": "className",
          "section": "Tooltip",
          "data": {
            "name": "className",
            "type": "string",
            "default": "",
            "required": "false",
            "description": "CSS Class Name"
          }
        },
        {
          "name": "tag",
          "section": "Tooltip",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "span",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "typography",
      "version": "0.0.1",
      "description": "Styles text in a consistent manner.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Headline",
          "description": "",
          "order": 1
        },
        {
          "name": "Body",
          "description": "",
          "order": 2
        },
        {
          "name": "Detail",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/display-one-typography",
            "github": "apps/workshop/src/examples/components/typography/display-one-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const DisplayOneTypography = () => {\n  return <Typography variant=\"display-1\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Display 1"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/display-two-typography",
            "github": "apps/workshop/src/examples/components/typography/display-two-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const DisplayTwoTypography = () => {\n  return <Typography variant=\"display-2\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Display 2"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/headline-one-typography",
            "github": "apps/workshop/src/examples/components/typography/headline-one-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const HeadlineOneTypography = () => {\n  return <Typography variant=\"headline-1\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Headline 1"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/headline-two-typography",
            "github": "apps/workshop/src/examples/components/typography/headline-two-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const HeadlineTwoTypography = () => {\n  return <Typography variant=\"headline-2\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Headline 2"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/headline-three-typography",
            "github": "apps/workshop/src/examples/components/typography/headline-three-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const HeadlineThreeTypography = () => {\n  return <Typography variant=\"headline-3\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Headline 3"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/headline-four-typography",
            "github": "apps/workshop/src/examples/components/typography/headline-four-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const HeadlineFourTypography = () => {\n  return <Typography variant=\"headline-4\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Headline 4"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/subtitle-one-typography",
            "github": "apps/workshop/src/examples/components/typography/subtitle-one-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const SubtitleOneTypography = () => {\n  return <Typography variant=\"subtitle-1\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Subtitle 1"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/subtitle-two-typography",
            "github": "apps/workshop/src/examples/components/typography/subtitle-two-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const SubtitleTwoTypography = () => {\n  return <Typography variant=\"subtitle-2\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Subtitle 2"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/subtitle-three-typography",
            "github": "apps/workshop/src/examples/components/typography/subtitle-three-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const SubtitleThreeTypography = () => {\n  return <Typography variant=\"subtitle-3\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Subtitle 3"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Headline",
          "url": {
            "iframe": "components/typography/overline-typography",
            "github": "apps/workshop/src/examples/components/typography/overline-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const OverlineTypography = () => {\n  return <Typography variant=\"overline\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Overline"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Body",
          "url": {
            "iframe": "components/typography/body-one-typography",
            "github": "apps/workshop/src/examples/components/typography/body-one-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const BodyOneTypography = () => {\n  return <Typography variant=\"body-1\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Body 1"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Body",
          "url": {
            "iframe": "components/typography/body-two-typography",
            "github": "apps/workshop/src/examples/components/typography/body-two-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const BodyTwoTypography = () => {\n  return <Typography variant=\"body-2\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Body 2"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Body",
          "url": {
            "iframe": "components/typography/body-two-bold-typography",
            "github": "apps/workshop/src/examples/components/typography/body-two-bold-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const BodyTwoBoldTypography = () => {\n  return <Typography variant=\"body-2-bold\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Body 2 bold"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Body",
          "url": {
            "iframe": "components/typography/body-two-medium-typography",
            "github": "apps/workshop/src/examples/components/typography/body-two-medium-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const BodyTwoMediumTypography = () => {\n  return <Typography variant=\"body-2-medium\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Body 2 medium"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Body",
          "url": {
            "iframe": "components/typography/body-three-typography",
            "github": "apps/workshop/src/examples/components/typography/body-three-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const BodyThreeTypography = () => {\n  return <Typography variant=\"body-3\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Body 3"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/button-medium-typography",
            "github": "apps/workshop/src/examples/components/typography/button-medium-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ButtonMediumTypography = () => {\n  return <Typography variant=\"button-medium\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Button medium"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/button-large-typography",
            "github": "apps/workshop/src/examples/components/typography/button-large-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ButtonLargeTypography = () => {\n  return <Typography variant=\"button-large\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Button large"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/button-small-typography",
            "github": "apps/workshop/src/examples/components/typography/button-small-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ButtonSmallTypography = () => {\n  return <Typography variant=\"button-small\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Button small"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/label-large-typography",
            "github": "apps/workshop/src/examples/components/typography/label-large-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const LabelLargeTypography = () => {\n  return <Typography variant=\"label-large\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n\nLabelLargeTypography.displayName = 'LabelLargeTypography';\n"
          },
          "name": "Label large"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/label-large-active-typography",
            "github": "apps/workshop/src/examples/components/typography/label-large-active-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const LabelLargeActiveTypography = () => {\n  return <Typography variant=\"label-large-active\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Label large active"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/label-typography",
            "github": "apps/workshop/src/examples/components/typography/label-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const LabelTypography = () => {\n  return <Typography variant=\"label\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Label"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/label-active-typography",
            "github": "apps/workshop/src/examples/components/typography/label-active-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const LabelActiveTypography = () => {\n  return <Typography variant=\"label-active\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Label active"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/label-small-typography",
            "github": "apps/workshop/src/examples/components/typography/label-small-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const LabelSmallTypography = () => {\n  return <Typography variant=\"label-small\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Label small"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/color-default-typography",
            "github": "apps/workshop/src/examples/components/typography/color-default-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ColorDefaultTypography = () => {\n  return <Typography colorScheme=\"default\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Typography color default"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/color-subtle-typography",
            "github": "apps/workshop/src/examples/components/typography/color-subtle-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ColorSubtleTypography = () => {\n  return <Typography colorScheme=\"subtle\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Typography color subtle"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/color-active-typography",
            "github": "apps/workshop/src/examples/components/typography/color-active-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ColorActiveTypography = () => {\n  return <Typography colorScheme=\"active\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Typography color active"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Detail",
          "url": {
            "iframe": "components/typography/color-on-active-typography",
            "github": "apps/workshop/src/examples/components/typography/color-on-active-typography.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Typography } from '@visa/nova-react';\n\nexport const ColorOnActiveTypography = () => {\n  return <Typography colorScheme=\"on-active\">The quick brown fox jumps over the lazy dog.</Typography>;\n};\n"
          },
          "name": "Typography color on active"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Typography",
          "selector": "<Typography />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Styles text in a consistent manner."
        }
      ],
      "properties": [
        {
          "name": "colorScheme",
          "section": "Typography",
          "data": {
            "name": "colorScheme",
            "type": "\"subtle\" , \"active\" , \"default\" , \"on-active\"",
            "default": "",
            "required": "false",
            "description": "Color variant"
          }
        },
        {
          "name": "tag",
          "section": "Typography",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "p",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "variant",
          "section": "Typography",
          "data": {
            "name": "variant",
            "type": "\"label\" , \"body-1\" , \"body-2-bold\" , \"body-2-link\" , \"body-2-medium\" , \"body-2\" , \"body-3\" , \"button-large\" , \"button-medium\" , \"button-small\" , \"display-1\" , \"display-2\" , \"headline-1\" , \"headline-2\" , \"headline-3\" , \"headline-4\" , \"label-active\" , \"label-large-active\" , \"label-large\" , \"label-small\" , \"overline\" , \"subtitle-1\" , \"subtitle-2\" , \"subtitle-3\"",
            "default": "",
            "required": "false",
            "description": "Style variant"
          }
        }
      ]
    },
    {
      "name": "vertical-navigation",
      "version": "0.0.1",
      "description": "Menu or panel next to the page content that links to important pages or features.",
      "libraryId": null,
      "category": "components",
      "exampleSections": [
        {
          "name": "Default vertical navigations",
          "description": "",
          "order": 1
        },
        {
          "name": "Custom vertical navigation",
          "description": "",
          "order": 2
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/default-vertical-navigation",
            "github": "apps/workshop/src/examples/components/vertical-navigation/default-vertical-navigation.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'default-vertical-navigation';\nconst navRegionAriaLabel = 'Default vertical navigation';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const DefaultVerticalNavigation = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./vertical-navigation\">{tabContent.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Default vertical navigation"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-with-active-element",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-with-active-element.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-with-active-element';\nconst navRegionAriaLabel = 'Vertical navigation with active element';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    active: true,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithActiveElement = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          aria-current={tabContent.active ? 'page' : false}\n                          element={<a href={tabContent.href}>{tabContent.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation with active element"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-with-icons",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-with-icons.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n  VisaStatisticsTiny,\n  VisaSettingsTiny,\n  VisaSecurityTiny,\n  VisaNotesTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-with-icons';\nconst navRegionAriaLabel = 'Vertical navigation with icons';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0}`,\n    icon: <VisaStatisticsTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1}`,\n    icon: <VisaSettingsTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2}`,\n    icon: <VisaSecurityTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3}`,\n    icon: <VisaNotesTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4}`,\n    icon: <VisaSupportTicketTiny />,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithIcons = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          element={\n                            <a href={tabContent.href}>\n                              {tabContent.icon}\n                              {tabContent.tabLabel}\n                            </a>\n                          }\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation with icons"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-with-nested-elements",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-with-nested-elements.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-with-nested-elements';\nconst navRegionAriaLabel = 'Vertical navigation with nested elements';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithNestedElements = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const [l1Label2Expanded, setL1Label2Expanded] = useState(false);\n  const [l1Label4Expanded, setL1Label4Expanded] = useState(false);\n  const [l2Label1Expanded, setL2Label1Expanded] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    <Tab>\n                      <Button colorScheme=\"tertiary\" element={<a href=\"./vertical-navigation\">L1 label 1</a>} />\n                    </Tab>\n                    <Tab>\n                      <Button\n                        aria-expanded={l1Label2Expanded}\n                        aria-controls={`${id}-l1-label2-sub-menu`}\n                        colorScheme=\"tertiary\"\n                        onClick={() => setL1Label2Expanded(!l1Label2Expanded)}\n                      >\n                        L1 label 2\n                        <TabSuffix element={l1Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                      </Button>\n                      <UtilityFragment vHide={!l1Label2Expanded}>\n                        <Tabs orientation=\"vertical\" id={`${id}-l1-label2-sub-menu`} aria-hidden={!l1Label2Expanded}>\n                          <Tab>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./vertical-navigation\">L2 label 1</a>} />\n                          </Tab>\n                          <Tab>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./vertical-navigation\">L2 label 2</a>} />\n                          </Tab>\n                        </Tabs>\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <Button colorScheme=\"tertiary\" element={<a href=\"./vertical-navigation\">L1 label 3</a>} />\n                    </Tab>\n                    <Tab>\n                      <Button\n                        aria-expanded={l1Label4Expanded}\n                        aria-controls={`${id}-l1-label4-sub-menu`}\n                        colorScheme=\"tertiary\"\n                        onClick={() => setL1Label4Expanded(!l1Label4Expanded)}\n                      >\n                        L1 label 4\n                        <TabSuffix element={l1Label4Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                      </Button>\n                      <UtilityFragment vHide={!l1Label4Expanded}>\n                        <Tabs orientation=\"vertical\" id={`${id}-l1-label4-sub-menu`} aria-hidden={!l1Label4Expanded}>\n                          <Tab>\n                            <Button\n                              aria-expanded={l2Label1Expanded}\n                              aria-controls={`${id}-l2-label1-sub-menu`}\n                              colorScheme=\"tertiary\"\n                              onClick={() => setL2Label1Expanded(!l2Label1Expanded)}\n                            >\n                              L2 label 1\n                              <TabSuffix element={l2Label1Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                            </Button>\n\n                            <UtilityFragment vHide={!l2Label1Expanded}>\n                              <Tabs\n                                orientation=\"vertical\"\n                                id={`${id}-l2-label1-sub-menu`}\n                                aria-hidden={!l2Label1Expanded}\n                              >\n                                <Tab>\n                                  <Button\n                                    colorScheme=\"tertiary\"\n                                    element={<a href=\"./vertical-navigation\">L3 label 1</a>}\n                                  />\n                                </Tab>\n                                <Tab>\n                                  <Button\n                                    colorScheme=\"tertiary\"\n                                    element={<a href=\"./vertical-navigation\">L3 label 2</a>}\n                                  />\n                                </Tab>\n                                <Tab>\n                                  <Button\n                                    colorScheme=\"tertiary\"\n                                    element={<a href=\"./vertical-navigation\">L3 label 3</a>}\n                                  />\n                                </Tab>\n                              </Tabs>\n                            </UtilityFragment>\n                          </Tab>\n                        </Tabs>\n                      </UtilityFragment>\n                    </Tab>\n                    <Tab>\n                      <Button colorScheme=\"tertiary\" element={<a href=\"./vertical-navigation\">L1 label 5</a>} />\n                    </Tab>\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation with nested elements"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-with-section-titles",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-with-section-titles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-with-section-titles';\nconst navRegionAriaLabel = 'Vertical navigation with section titles';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithSectionTitles = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    <Tab>\n                      <UtilityFragment>\n                        <Tab sectionTitle tag=\"h2\">\n                          Section Title 1\n                        </Tab>\n                      </UtilityFragment>\n                      <Tabs orientation=\"vertical\">\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 1</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 2</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 3</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                      </Tabs>\n                    </Tab>\n                    <Tab>\n                      <UtilityFragment>\n                        <Tab sectionTitle tag=\"h2\">\n                          Section Title 2\n                        </Tab>\n                      </UtilityFragment>\n                      <Tabs orientation=\"vertical\">\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 4</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 5</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                        <Tab>\n                          <UtilityFragment>\n                            <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 6</a>} />\n                          </UtilityFragment>\n                        </Tab>\n                      </Tabs>\n                    </Tab>\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation with section titles"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-with-nested-elements-and-section-titles",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-with-nested-elements-and-section-titles.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-with-nested-elements-and-section-titles';\nconst navRegionAriaLabel = 'Vertical navigation with nested elements and section titles';\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithNestedElementsAndSectionTitles = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n  const [l1Label2Expanded, setL1Label2Expanded] = useState(false);\n  const [l2Label2Expanded, setL2Label2Expanded] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    <Tab>\n                      <Tab sectionTitle tag=\"h2\">\n                        L1 Section Title 1\n                      </Tab>\n                      <Tabs orientation=\"vertical\">\n                        <Tab>\n                          <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 1</a>} />\n                        </Tab>\n                        <Tab>\n                          <Button\n                            aria-expanded={l1Label2Expanded}\n                            aria-controls={`${id}-l1-label2-sub-menu`}\n                            colorScheme=\"tertiary\"\n                            onClick={() => setL1Label2Expanded(!l1Label2Expanded)}\n                          >\n                            L1 label 2\n                            <TabSuffix element={l1Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                          </Button>\n                          <UtilityFragment vHide={!l1Label2Expanded}>\n                            <Tabs\n                              orientation=\"vertical\"\n                              id={`${id}-l1-label2-sub-menu`}\n                              tag=\"div\"\n                            >\n                              <Tab sectionTitle tag=\"h3\">\n                                L2 Section Title 1\n                              </Tab>\n                              <Tabs orientation=\"vertical\">\n                                <Tab>\n                                  <Button\n                                    colorScheme=\"tertiary\"\n                                    element={<a href=\"./navigation-drawer\">L2 label 1</a>}\n                                  />\n                                </Tab>\n                                <Tab>\n                                  <Button\n                                    aria-expanded={l2Label2Expanded}\n                                    aria-controls={`${id}-l2-label2-sub-menu`}\n                                    colorScheme=\"tertiary\"\n                                    onClick={() => setL2Label2Expanded(!l2Label2Expanded)}\n                                  >\n                                    L2 label 2\n                                    <TabSuffix\n                                      element={l2Label2Expanded ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n                                    />\n                                  </Button>\n\n                                  <UtilityFragment vHide={!l2Label2Expanded}>\n                                    <Tabs orientation=\"vertical\" id={`${id}-l2-label2-sub-menu`} tag=\"div\">\n                                      <Tab sectionTitle tag=\"h4\">\n                                        L3 Section Title 1\n                                      </Tab>\n                                      <Tabs orientation=\"vertical\">\n                                        <Tab>\n                                          <Button\n                                            colorScheme=\"tertiary\"\n                                            element={<a href=\"./navigation-drawer\">L3 label 1</a>}\n                                          />\n                                        </Tab>\n                                        <Tab>\n                                          <Button\n                                            colorScheme=\"tertiary\"\n                                            element={<a href=\"./navigation-drawer\">L3 label 2</a>}\n                                          />\n                                        </Tab>\n                                      </Tabs>\n                                    </Tabs>\n                                  </UtilityFragment>\n                                </Tab>\n                              </Tabs>\n                            </Tabs>\n                          </UtilityFragment>\n                        </Tab>\n                      </Tabs>\n                    </Tab>\n                    <Tab>\n                      <Tab sectionTitle tag=\"h2\">\n                        L1 Section Title 2\n                      </Tab>\n                      <Tabs orientation=\"vertical\">\n                        <Tab>\n                          <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 3</a>} />\n                        </Tab>\n                        <Tab>\n                          <Button colorScheme=\"tertiary\" element={<a href=\"./navigation-drawer\">L1 label 4</a>} />\n                        </Tab>\n                      </Tabs>\n                    </Tab>\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation with nested elements and section titles"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/alternate-vertical-navigation",
            "github": "apps/workshop/src/examples/components/vertical-navigation/alternate-vertical-navigation.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-vertical-navigation';\nconst navRegionAriaLabel = 'Alternate vertical navigation';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const AlternateVerticalNavigation = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} alternate orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link alternate skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button colorScheme=\"tertiary\" element={<a href={tabContent.href}>{tabContent.tabLabel}</a>} />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                iconTwoColor\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate vertical navigation"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/alternate-vertical-navigation-with-active-element",
            "github": "apps/workshop/src/examples/components/vertical-navigation/alternate-vertical-navigation-with-active-element.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-vertical-navigation-with-active-element';\nconst navRegionAriaLabel = 'Alternate vertical navigation with active element';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    active: true,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const AlternateVerticalNavigationWithActiveElement = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} alternate orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link alternate skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button\n                          aria-current={tabContent.active ? 'page' : false}\n                          colorScheme=\"tertiary\"\n                          element={<a href={tabContent.href}>{tabContent.tabLabel}</a>}\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                iconTwoColor\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate vertical navigation with active element"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Default vertical navigations",
          "url": {
            "iframe": "components/vertical-navigation/alternate-vertical-navigation-with-icons",
            "github": "apps/workshop/src/examples/components/vertical-navigation/alternate-vertical-navigation-with-icons.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n  VisaStatisticsTiny,\n  VisaSettingsTiny,\n  VisaSecurityTiny,\n  VisaNotesTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'alternate-vertical-navigation-with-icons';\nconst navRegionAriaLabel = 'Alternate vertical navigation with icons';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0}`,\n    icon: <VisaStatisticsTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1}`,\n    icon: <VisaSettingsTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2}`,\n    icon: <VisaSecurityTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3}`,\n    icon: <VisaNotesTiny />,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4}`,\n    icon: <VisaSupportTicketTiny />,\n    href: './vertical-navigation',\n  },\n];\n\nconst accountSubItems = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-account-sub-item-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-account-sub-item-1`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const AlternateVerticalNavigationWithIcons = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} alternate orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link alternate skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <UtilityFragment\n                vFlex\n                vFlexCol\n                vGap={12}\n                vMarginTop={16}\n                vMarginRight={16}\n                vMarginBottom={30}\n                vMarginLeft={20}\n              >\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"https://www.visa.com\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <NavAppName>\n                    <Typography variant=\"subtitle-1\">Application Name</Typography>\n                  </NavAppName>\n                </Link>\n              </UtilityFragment>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button\n                          colorScheme=\"tertiary\"\n                          iconTwoColor\n                          element={\n                            <a href={tabContent.href}>\n                              {tabContent.icon}\n                              {tabContent.tabLabel}\n                            </a>\n                          }\n                        />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            {navExpanded && (\n              <>\n                <Divider dividerType=\"decorative\" />\n                <Tab tag=\"div\">\n                  <Button\n                    aria-expanded={accountTabOpen}\n                    aria-controls={`${id}-account-sub-menu`}\n                    aria-label=\"Alex Miller\"\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    onClick={() => setAccountTabOpen(!accountTabOpen)}\n                  >\n                    <VisaAccountTiny />\n                    Alex Miller\n                    <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                  </Button>\n                  <UtilityFragment vHide={!accountTabOpen}>\n                    <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                      {accountSubItems.map(accountSubItem => (\n                        <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                          <Button\n                            colorScheme=\"tertiary\"\n                            element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                          />\n                        </Tab>\n                      ))}\n                    </Tabs>\n                  </UtilityFragment>\n                </Tab>\n              </>\n            )}\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate vertical navigation with icons"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Custom vertical navigation",
          "url": {
            "iframe": "components/vertical-navigation/vertical-navigation-without-logo-or-application-name",
            "github": "apps/workshop/src/examples/components/vertical-navigation/vertical-navigation-without-logo-or-application-name.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaMediaFastForwardTiny, VisaMediaRewindTiny } from '@visa/nova-icons-react';\nimport { Button, Link, Nav, Tab, Tabs, Typography, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\nimport Styles from './styles.module.scss';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'vertical-navigation-without-logo-or-application-name';\nconst navRegionAriaLabel = 'Vertical navigation without logo or application name';\n\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    href: './vertical-navigation',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    href: './vertical-navigation',\n  },\n];\n\n/*\n * Styles for the application container and main content\n * -----------------------------------------------------\n * .appContainer {\n *   &:global(:has(.v-nav .v-tabs)) {\n *     // The open navigation should be 242px\n *     grid-template-columns: 242px 1fr;\n *   }\n * }\n *\n * .layoutContainer {\n *   min-block-size: 700px;\n *   display: grid;\n *   grid-template-columns: auto 1fr;\n * }\n *\n * .mainContent {\n *   background-color: whitesmoke;\n *   min-block-size: 300px;\n *   padding: 12px;\n * }\n */\n\nexport const VerticalNavigationWithoutLogoOrApplicationName = () => {\n  const [navExpanded, setNavExpanded] = useState(true);\n\n  return (\n    <div className={Styles.appContainer}>\n      <div id=\"layout\" className={Styles.layoutContainer}>\n        <Nav id={id} orientation=\"vertical\" tag=\"header\">\n          {navExpanded && (\n            <Link skipLink href=\"#content\">\n              Skip to content\n            </Link>\n          )}\n          {navExpanded && (\n            <>\n              <nav aria-label={navRegionAriaLabel}>\n                <UtilityFragment vGap={8}>\n                  <Tabs orientation=\"vertical\">\n                    {tabsContent.map(tabContent => (\n                      <Tab key={tabContent.id}>\n                        <Button colorScheme=\"tertiary\" element={<a href={tabContent.href}>{tabContent.tabLabel}</a>} />\n                      </Tab>\n                    ))}\n                  </Tabs>\n                </UtilityFragment>\n              </nav>\n            </>\n          )}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n            <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n              <Button\n                aria-label=\"Side bar\"\n                aria-expanded={!!navExpanded}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => setNavExpanded(!navExpanded)}\n                subtle\n              >\n                {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n              </Button>\n            </UtilityFragment>\n          </Utility>\n        </Nav>\n        <div className={Styles.mainContent}>\n          <Typography>Main Content</Typography>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
          },
          "name": "Vertical navigation without logo or application name"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Nav",
          "selector": "<Nav />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Menu or panel at the top or next to page content that links to important pages or features."
        },
        {
          "order": 2,
          "name": "tabs",
          "type": "related",
          "selector": "<Tabs />",
          "description": ""
        }
      ],
      "properties": [
        {
          "name": "alternate",
          "section": "Nav",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate"
          }
        },
        {
          "name": "drawer",
          "section": "Nav",
          "data": {
            "name": "drawer",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Drawer"
          }
        },
        {
          "name": "orientation",
          "section": "Nav",
          "data": {
            "name": "orientation",
            "type": "\"horizontal\" , \"vertical\"",
            "default": "",
            "required": "false",
            "description": "Orientation"
          }
        },
        {
          "name": "tag",
          "section": "Nav",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "nav",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "application-layouts",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "patterns",
      "exampleSections": [
        {
          "name": "Horizontal application layouts",
          "description": "",
          "order": 1
        },
        {
          "name": "Stacked horizontal application layouts",
          "description": "",
          "order": 2
        },
        {
          "name": "Vertical application layouts",
          "description": "",
          "order": 3
        },
        {
          "name": "Mixed application layouts",
          "description": "",
          "order": 4
        },
        {
          "name": "Shared Components",
          "description": "",
          "order": 5
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal application layouts",
          "url": {
            "iframe": "patterns/application-layouts/horizontal-application-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/horizontal-application-layout.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/application-layouts/horizontal-application-layout.tsx": "import { HorizontalNavLayout } from './horizontal-nav-layout';\nimport { FooterLayout } from './shared/footer-layout';\nimport './styles-horizontal.css';\n\n/**\n * Shell layout with navigation bar at the top, content scrolls below. Most common layout for web applications.\n */\nexport const HorizontalApplicationLayout = () => {\n  return (\n    <>\n      <div className=\"layout layout-example layout-horizontal\">\n        {/* Fixed header region - remains visible during scroll */}\n        <div className=\"layout-header\">\n          <HorizontalNavLayout />\n        </div>\n        {/* Scrollable content region - target for skip link navigation */}\n        <div id=\"content\" className=\"layout-content\" tabIndex={-1}>\n          <main className=\"layout-main\">{/* Add your h1 and page content here */}</main>\n          <FooterLayout />\n        </div>\n      </div>\n    </>\n  );\n};\n"
          },
          "name": "Horizontal application layout"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal application layouts",
          "url": {
            "iframe": "patterns/application-layouts/horizontal-nav-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/horizontal-nav-layout.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/horizontal-nav-layout.tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// Base ID for aria attributes and element IDs - customize for unique identification\nconst id = 'horizontal-nav';\n\n// Account dropdown menu items - replace with real user profile actions\nconst accountSubItems = [\n  {\n    tabLabel: 'Account item 1',\n    id: `${id}-account-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'Account item 2',\n    id: `${id}-account-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n// Submenu items for navigation tab with dropdown - replace with actual sub-navigation\nconst label4SubItems = [\n  {\n    tabLabel: 'L1 label 4 item 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 4 item 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n/**\n * Top navigation bar component used by HorizontalApplicationLayout.\n */\nexport const HorizontalNavLayout = () => {\n  // Refs for managing keyboard focus on search input and button\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  // State for desktop dropdown menus\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [label4Open, setLabel4Open] = useState(false);\n\n  // State for mobile menu and its nested dropdowns\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel4MenuOpen, setMobileLabel4MenuOpen] = useState(false);\n\n  // Search UI state\n  const [expandSearch, setExpandSearch] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  // Moves focus to search input when expanded, back to button when collapsed\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // Setup for account dropdown: handles positioning and interactions\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // Setup for navigation dropdown (label4): handles positioning and interactions\n  const {\n    context: label4FloatingContext,\n    floatingStyles: label4FloatingStyles,\n    refs: label4FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label4Open,\n    onOpenChange: setLabel4Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel4Ref = useClick(label4FloatingContext);\n  const dismissLabel4Menu = useDismiss(label4FloatingContext);\n  const { getReferenceProps: getLabel4ReferenceProps, getFloatingProps: getLabel4FloatingProps } = useInteractions([\n    clickLabel4Ref,\n    dismissLabel4Menu,\n  ]);\n\n  // Toggles mobile navigation drawer open and closed\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        {/* Main navigation container */}\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {/* Default nav: logo, tabs, actions */}\n          {!expandSearch ? (\n            <>\n              {/* Mobile menu toggle button */}\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              {/* Logo and app name */}\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./application-layouts\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <UtilityFragment vContainerHide=\"mobile\">\n                    <NavAppName>\n                      <Utility\n                        vContainerHide=\"xs\"\n                        element={<Typography variant=\"headline-3\">Application name</Typography>}\n                      />\n                    </NavAppName>\n                  </UtilityFragment>\n                </Link>\n              </UtilityFragment>\n              {/* Desktop navigation tabs - hidden on mobile */}\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"global\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 3</a>}\n                        />\n                      </Tab>\n                      {/* Tab with dropdown submenu */}\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label4Open}\n                          aria-controls={label4Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label4FloatingRefs.setReference}\n                          {...getLabel4ReferenceProps()}\n                        >\n                          L1 label 4<TabSuffix element={label4Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label4Open && (\n                          <FloatingFocusManager\n                            context={label4FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label4Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label4FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label4FloatingRefs.setFloating}\n                              {...getLabel4FloatingProps()}\n                            >\n                              <Listbox>\n                                {label4SubItems.map(label4SubItem => (\n                                  <li key={label4SubItem.id}>\n                                    <ListboxItem<'a'> href={label4SubItem.href} tag=\"a\">\n                                      {label4SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 5</a>}\n                        />\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              {/* Action buttons: search, notifications, account */}\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  ref={searchButtonRef}\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => {\n                    setExpandSearch(true);\n                    searchInitiallyActivated.current = true;\n                  }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                {/* Notifications button with badge */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                {/* Account dropdown menu */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            /* Expanded search replaces entire nav bar */\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      {/* Mobile navigation drawer */}\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav aria-label=\"global menu\" aria-hidden={!mobileMenuOpen} id={`${id}-mobile-menu`} orientation=\"vertical\">\n          {/* Mobile nav items */}\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 1</a>}\n              />\n            </Tab>\n            {/* Tab with expandable submenu in mobile */}\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 3</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel4MenuOpen}\n                aria-controls={mobileLabel4MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel4MenuOpen(!mobileLabel4MenuOpen)}\n              >\n                L1 label 4\n                <TabSuffix element={mobileLabel4MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel4MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label4SubItems.map(label4SubItem => (\n                    <Tab key={label4SubItem.id} id={label4SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label4SubItem.href}>{label4SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            {/* Notifications item (badge inline on mobile) */}\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge\n                  badgeVariant=\"number\"\n                  style={\n                    {\n                      position: 'relative',\n                    } as CSSProperties\n                  }\n                  tag=\"sup\"\n                >\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n          </Tabs>\n          <UtilityFragment vMarginTop={5}>\n            <Divider dividerType=\"decorative\" />\n          </UtilityFragment>\n          {/* Account section at bottom of mobile menu */}\n          <UtilityFragment vMarginTop={6} className=\"v-tabs-vertical\">\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </UtilityFragment>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Horizontal nav"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Horizontal application layouts",
          "url": {
            "iframe": "patterns/application-layouts/styles-horizontal",
            "github": "apps/workshop/src/examples/patterns/application-layouts/styles-horizontal.css"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/styles-horizontal.css": "/* Layout structure with header on top and content below, filling full viewport */\n.layout-horizontal {\n  height: 100vh;\n  z-index: 1;\n  display: grid;\n  grid-template-columns: 1fr;\n  grid-template-rows: auto 1fr;\n  grid-template-areas: 'header' 'content';\n  background-color: var(--palette-default-surface-3, #f0f0f0);\n}\n\n/* Higher z-index keeps header above other elements when scrolling */\n.layout-horizontal .layout-header {\n  z-index: 3;\n  position: relative;\n  grid-area: header;\n}\n\n/* Allows content area to scroll independently while header stays fixed */\n.layout-horizontal .layout-content {\n  position: relative;\n  overflow-y: auto;\n  display: flex;\n  flex-direction: column;\n  grid-area: content;\n}\n\n/* Main content grows to fill available space, pushing footer to bottom */\n.layout-horizontal main {\n  display: block;\n  flex-grow: 1;\n}\n\n.layout-horizontal header.v-nav {\n  position: relative;\n}\n\n/* Match footer background to overall page background */\n.layout-horizontal footer {\n  --v-footer-background-color: var(--v-palette-default-surface-3);\n}\n\n/* Show/hide elements based on screen size for mobile and desktop views */\n@container (max-width: 1003px) {\n  .layout-horizontal .v-mobile-container-hide {\n    display: none;\n  }\n  .layout-horizontal .v-desktop-container-hide {\n    display: block;\n  }\n  .layout-horizontal .v-desktop-container-hide.v-hide {\n    display: none;\n  }\n}\n@container (min-width: 1004px) {\n  .layout-horizontal .v-mobile-container-hide {\n    display: flex;\n  }\n  .layout-horizontal .v-desktop-container-hide {\n    display: none;\n  }\n}\n"
          },
          "name": "Styles horizontal"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked horizontal application layouts",
          "url": {
            "iframe": "patterns/application-layouts/stacked-horizontal-application-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/stacked-horizontal-application-layout.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/application-layouts/stacked-horizontal-application-layout.tsx": "import { FooterLayout } from './shared/footer-layout';\nimport './styles-stacked.css';\nimport { StackedHorizontalNavLayout } from './stacked-horizontal-nav-layout';\n\n/**\n * Shell layout with two navigation bars stacked at the top. Use when you have both global navigation and page-level tabs.\n */\nexport const StackedHorizontalApplicationLayout = () => {\n  return (\n    <>\n      <div className=\"layout layout-example layout-stacked\">\n        {/* Fixed stacked header region - contains two navigation bars */}\n        <div className=\"layout-header\">\n          <StackedHorizontalNavLayout />\n        </div>\n        {/* Scrollable content region - target for skip link navigation */}\n        <div id=\"content\" className=\"layout-content\" tabIndex={-1}>\n          <main className=\"layout-main\">{/* Add your h1 and page content here */}</main>\n          <FooterLayout />\n        </div>\n      </div>\n    </>\n  );\n};\n"
          },
          "name": "Stacked horizontal application layout"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Stacked horizontal application layouts",
          "url": {
            "iframe": "patterns/application-layouts/stacked-horizontal-nav-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/stacked-horizontal-nav-layout.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/stacked-horizontal-nav-layout.tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useDismiss,\n  useFloating,\n  useInteractions,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  Tabs,\n  TabSuffix,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n  Divider,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// Base ID for aria attributes and element IDs - customize for unique identification\nconst id = 'stacked-horizontal-nav';\n\n// Account dropdown menu items - replace with real user profile actions\nconst accountSubItems = [\n  {\n    tabLabel: 'Account item 1',\n    id: `${id}-account-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'Account item 2',\n    id: `${id}-account-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n/**\n * Two-tier navigation component used by StackedHorizontalApplicationLayout.\n */\nexport const StackedHorizontalNavLayout = () => {\n  // Refs for managing keyboard focus on search input and button\n  const searchInputRef = useRef<HTMLInputElement | null>(null);\n  const searchButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  // State for desktop account dropdown\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n\n  // State for mobile menu and nested account dropdown\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n\n  // Search UI state\n  const [expandSearch, setExpandSearch] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  // Moves focus to search input when expanded, back to button when collapsed\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // Setup for account dropdown: handles positioning and interactions\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // Toggles mobile navigation drawer open and closed\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\">\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        {/* Upper navigation bar: logo, utilities */}\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\">\n          {/* Default nav: logo, actions */}\n          {!expandSearch ? (\n            <>\n              {/* Mobile menu toggle button */}\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              {/* Logo and app name */}\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./application-layouts\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <UtilityFragment vContainerHide=\"mobile\">\n                    <NavAppName>\n                      <Utility\n                        vContainerHide=\"xs\"\n                        element={<Typography variant=\"headline-3\">Application name</Typography>}\n                      />\n                    </NavAppName>\n                  </UtilityFragment>\n                </Link>\n              </UtilityFragment>\n\n              {/* Action buttons: search, notifications, account */}\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  ref={searchButtonRef}\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => {\n                    setExpandSearch(true);\n                    searchInitiallyActivated.current = true;\n                  }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                {/* Notifications button with badge */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                {/* Account dropdown menu */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            /* Expanded search replaces entire upper nav bar */\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n\n      {/* Mobile navigation drawer */}\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav aria-label=\"global menu\" aria-hidden={!mobileMenuOpen} id={`${id}-mobile-menu`} orientation=\"vertical\">\n          {/* Mobile nav items - dynamically generated, replace with your navigation */}\n          <Tabs orientation=\"vertical\">\n            {Array.from({ length: 3 }).map((_, contextIndex) => {\n              return (\n                <Tab key={`mobile-l1-item-${contextIndex}`}>\n                  <Button\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    element={<a href=\"./application-layouts\">L1 label {contextIndex + 1}</a>}\n                  />\n                </Tab>\n              );\n            })}\n            {/* Notifications item (badge inline on mobile) */}\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge\n                  badgeVariant=\"number\"\n                  style={\n                    {\n                      position: 'relative',\n                    } as CSSProperties\n                  }\n                  tag=\"sup\"\n                >\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n          </Tabs>\n          <UtilityFragment vMarginTop={5}>\n            <Divider dividerType=\"decorative\" />\n          </UtilityFragment>\n          {/* Account section at bottom of mobile menu */}\n          <UtilityFragment vMarginTop={6} className=\"v-tabs-vertical\">\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </UtilityFragment>\n        </Nav>\n      </UtilityFragment>\n\n      {/* Lower desktop navigation bar: primary tabs - hidden on mobile */}\n      <Nav\n        aria-label=\"secondary\"\n        className=\"v-ml-auto v-mobile-container-hide\"\n        style={\n          {\n            '--v-surface-background': 'var(--palette-default-surface-2)',\n            '--v-tabs-active-line-padding': 'var(--size-responsive-10)',\n          } as CSSProperties\n        }\n      >\n        {/* Primary navigation tabs - dynamically generated, replace with your navigation */}\n        <Tabs className=\"v-gap-8\">\n          {Array.from({ length: 3 }).map((_, index) => {\n            return (\n              <Tab key={`second-tier-item-${index}`}>\n                <Button\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  element={<a href=\"./application-layouts\">L1 label {index + 1}</a>}\n                />\n              </Tab>\n            );\n          })}\n        </Tabs>\n      </Nav>\n    </div>\n  );\n};\n"
          },
          "name": "Stacked horizontal nav"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical application layouts",
          "url": {
            "iframe": "patterns/application-layouts/vertical-application-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/vertical-application-layout.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/application-layouts/vertical-application-layout.tsx": "import { FooterLayout } from './shared/footer-layout';\nimport './styles-vertical.css';\nimport { VerticalNavigationLayout } from './vertical-nav-layout';\n\n/**\n * Shell layout with collapsible sidebar on the left, content on the right. Common for dashboards and admin tools.\n */\nexport const VerticalApplicationLayout = () => {\n  return (\n    <>\n      <div className=\"layout layout-example layout-vertical\">\n        {/* Left sidebar region - collapsible navigation */}\n        <div className=\"layout-header v-flex v-flex-col v-gap-24\">\n          <VerticalNavigationLayout />\n        </div>\n        {/* Scrollable content region - target for skip link navigation */}\n        <div id=\"content\" className=\"layout-content\" tabIndex={-1}>\n          <main className=\"layout-main\">{/* Add your h1 and page content here */}</main>\n          <FooterLayout />\n        </div>\n      </div>\n    </>\n  );\n};\n"
          },
          "name": "Vertical application layout"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical application layouts",
          "url": {
            "iframe": "patterns/application-layouts/vertical-nav-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/vertical-nav-layout.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/vertical-nav-layout.tsx": "import {\n  VisaAccountTiny,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n  VisaStatisticsTiny,\n  VisaSettingsTiny,\n  VisaSecurityTiny,\n  VisaNotesTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\n// Base ID for aria attributes and element IDs - customize for unique identification\nconst id = 'vertical-no-main-navigation';\n\n// Navigation tab items with icons - customize labels, icons, and hrefs for your app\nconst tabsContent = [\n  {\n    tabLabel: 'L1 label 1',\n    id: `${id}-tab-0`,\n    icon: <VisaStatisticsTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 2',\n    id: `${id}-tab-1`,\n    icon: <VisaSettingsTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 3',\n    id: `${id}-tab-2`,\n    icon: <VisaSecurityTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 4',\n    id: `${id}-tab-3`,\n    icon: <VisaNotesTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 5',\n    id: `${id}-tab-4`,\n    icon: <VisaSupportTicketTiny />,\n    href: './application-layouts',\n  },\n];\n\n// Account dropdown menu items - replace with real user profile actions\nconst accountSubItems = [\n  {\n    tabLabel: 'Account item 1',\n    id: `${id}-account-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'Account item 2',\n    id: `${id}-account-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n/**\n * Left sidebar navigation component used by VerticalApplicationLayout.\n */\nexport const VerticalNavigationLayout = () => {\n  // Controls whether sidebar is expanded (with labels) or collapsed (icons only)\n  const [navExpanded, setNavExpanded] = useState(true);\n  // Controls whether account dropdown menu is open\n  const [accountTabOpen, setAccountTabOpen] = useState(false);\n\n  return (\n    <Nav id={id} orientation=\"vertical\" tag=\"header\">\n      {navExpanded && (\n        <Link skipLink href=\"#content\">\n          Skip to content\n        </Link>\n      )}\n      {/* Logo, app name, and navigation tabs - hidden when collapsed */}\n      {navExpanded && (\n        <>\n          <UtilityFragment\n            vFlex\n            vFlexCol\n            vGap={12}\n            vMarginTop={16}\n            vMarginRight={16}\n            vMarginBottom={30}\n            vMarginLeft={20}\n          >\n            <Link\n              aria-label=\"Visa Application Name Home\"\n              href=\"https://www.visa.com\"\n              id={`${id}-home-link`}\n              noUnderline\n              style={{ backgroundColor: 'transparent' }}\n            >\n              <VisaLogo />\n              <NavAppName>\n                <Typography variant=\"subtitle-1\">Application name</Typography>\n              </NavAppName>\n            </Link>\n          </UtilityFragment>\n          {/* Main navigation tabs with icons and labels */}\n          <nav aria-label=\"global\">\n            <UtilityFragment vGap={8}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <Button\n                      colorScheme=\"tertiary\"\n                      element={\n                        <a href=\"./application-layouts\">\n                          {tabContent.icon}\n                          {tabContent.tabLabel}\n                        </a>\n                      }\n                    />\n                  </Tab>\n                ))}\n              </Tabs>\n            </UtilityFragment>\n          </nav>\n        </>\n      )}\n      {/* Footer section: account menu (when expanded) and collapse toggle */}\n      <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n        {/* Account menu with expandable submenu */}\n        {navExpanded && (\n          <>\n            <Divider dividerType=\"decorative\" />\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={accountTabOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setAccountTabOpen(!accountTabOpen)}\n              >\n                <VisaAccountTiny />\n                Alex Miller\n                <TabSuffix element={accountTabOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              <UtilityFragment vHide={!accountTabOpen}>\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`} aria-hidden={!accountTabOpen}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              </UtilityFragment>\n            </Tab>\n          </>\n        )}\n        {/* Collapse/expand toggle button */}\n        <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n          <Button\n            aria-label=\"Side bar\"\n            aria-expanded={!!navExpanded}\n            buttonSize=\"small\"\n            colorScheme=\"tertiary\"\n            iconButton\n            onClick={() => setNavExpanded(!navExpanded)}\n            subtle\n          >\n            {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n          </Button>\n        </UtilityFragment>\n      </Utility>\n    </Nav>\n  );\n};\n"
          },
          "name": "Vertical nav"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Vertical application layouts",
          "url": {
            "iframe": "patterns/application-layouts/styles-vertical",
            "github": "apps/workshop/src/examples/patterns/application-layouts/styles-vertical.css"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/styles-vertical.css": "/* Layout with sidebar navigation on left and main content on right, both filling full height */\n.layout-vertical {\n    height: 100vh;\n    display: grid;\n    grid-template-columns: auto 1fr;\n    grid-template-rows: 100%;\n    grid-template-areas: \"header content\";\n    background-color: var(--palette-default-surface-3, #f0f0f0);\n}\n\n/* When sidebar navigation is expanded, set fixed width for consistent spacing */\n.layout-vertical:has(.v-nav .v-tabs) {\n    grid-template-columns: 242px 1fr;\n}\n\n/* Higher z-index keeps sidebar navigation above other elements */\n.layout-vertical .layout-header {\n    z-index: 3;\n    position: relative;\n    grid-area: header;\n}\n\n/* Allows content area to scroll independently while sidebar stays fixed */\n.layout-vertical .layout-content {\n    position: relative;\n    overflow-y: auto;\n    display: flex;\n    flex-direction: column;\n    grid-area: content;\n}\n\n/* Main content grows to fill available space, pushing footer to bottom */\n.layout-vertical main {\n    display: block;\n    flex-grow: 1;\n}\n\n/* Match footer background to overall page background */\n.layout-vertical footer {\n  --v-footer-background-color: var(--v-palette-default-surface-3);\n}"
          },
          "name": "Styles vertical"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Mixed application layouts",
          "url": {
            "iframe": "patterns/application-layouts/mixed-application-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/mixed-application-layout.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/application-layouts/mixed-application-layout.tsx": "import { AlternateHorizontalNavLayout } from './alternate-horizontal-nav-layout';\nimport { FooterLayout } from './shared/footer-layout';\nimport './styles-mixed.css';\nimport { VerticalMixedNavLayout } from './vertical-mixed-nav-layout';\n\n/**\n * Shell layout with top navigation bar plus left sidebar. Use for complex apps with two levels of navigation.\n */\nexport const MixedApplicationLayout = () => {\n  return (\n    <>\n      <div className=\"layout layout-example layout-mixed\">\n        {/* Top horizontal navigation - primary level */}\n        <div className=\"layout-header\">\n          <AlternateHorizontalNavLayout />\n        </div>\n        {/* Left sidebar navigation - secondary level, collapsible */}\n        <VerticalMixedNavLayout />\n        {/* Scrollable content region - target for skip link navigation */}\n        <div id=\"content\" className=\"layout-content\" tabIndex={-1}>\n          <main className=\"layout-main\">{/* Add your h1 and page content here */}</main>\n          <FooterLayout />\n        </div>\n      </div>\n    </>\n  );\n};\n"
          },
          "name": "Mixed application layout"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Mixed application layouts",
          "url": {
            "iframe": "patterns/application-layouts/alternate-horizontal-nav-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/alternate-horizontal-nav-layout.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/alternate-horizontal-nav-layout.tsx": "import {\n  autoUpdate,\n  FloatingFocusManager,\n  offset,\n  useClick,\n  useFloating,\n  useInteractions,\n  useDismiss,\n} from '@floating-ui/react';\nimport {\n  VisaAccountLow,\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaCloseLow,\n  VisaCloseTiny,\n  VisaMenuLow,\n  VisaNotificationsLow,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Avatar,\n  Badge,\n  Button,\n  Divider,\n  DropdownButton,\n  DropdownMenu,\n  Input,\n  InputContainer,\n  Link,\n  Listbox,\n  ListboxItem,\n  Nav,\n  NavAppName,\n  Surface,\n  Tab,\n  TabSuffix,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n  VisaLogo,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\n// Base ID for aria attributes and element IDs - customize for unique identification\nconst id = 'alternate-horizontal-nav';\n\n// Account dropdown menu items - replace with real user profile actions\nconst accountSubItems = [\n  {\n    tabLabel: 'Account item 1',\n    id: `${id}-account-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'Account item 2',\n    id: `${id}-account-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n// Submenu items for navigation tab with dropdown - replace with actual sub-navigation\nconst label4SubItems = [\n  {\n    tabLabel: 'L1 label 4 item 1',\n    id: `${id}-label-3-sub-item-0`,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L1 label 4 item 2',\n    id: `${id}-label-3-sub-item-1`,\n    href: './application-layouts',\n  },\n];\n\n/**\n * Top navigation bar with dark theme, used by MixedApplicationLayout.\n * Similar to HorizontalNavLayout but with alternate styling.\n */\nexport const AlternateHorizontalNavLayout = () => {\n  // Refs for managing keyboard focus on search input and button\n  const searchInputRef = useRef<HTMLInputElement>(null);\n  const searchButtonRef = useRef<HTMLButtonElement>(null);\n\n  // State for desktop dropdown menus\n  const [accountMenuOpen, setAccountMenuOpen] = useState(false);\n  const [label4Open, setLabel4Open] = useState(false);\n\n  // State for mobile menu and its nested dropdowns\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [mobileAccountMenuOpen, setMobileAccountMenuOpen] = useState(false);\n  const [mobileLabel4MenuOpen, setMobileLabel4MenuOpen] = useState(false);\n\n  // Search UI state\n  const [expandSearch, setExpandSearch] = useState(false);\n  const searchInitiallyActivated = useRef(false);\n\n  // Moves focus to search input when expanded, back to button when collapsed\n  useEffect(() => {\n    if (expandSearch && searchInitiallyActivated.current) {\n      searchInputRef.current?.focus();\n    }\n    if (!expandSearch && searchInitiallyActivated.current) {\n      searchButtonRef.current?.focus();\n    }\n  }, [expandSearch]);\n\n  // Setup for account dropdown: handles positioning and interactions\n  const {\n    context: accountFloatingContext,\n    floatingStyles: accountFloatingStyles,\n    refs: accountFloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: accountMenuOpen,\n    onOpenChange: setAccountMenuOpen,\n    placement: 'bottom-end',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickAccountRef = useClick(accountFloatingContext);\n  const dismissAccountMenu = useDismiss(accountFloatingContext);\n  const { getReferenceProps: getAccountReferenceProps, getFloatingProps: getAccountFloatingProps } = useInteractions([\n    clickAccountRef,\n    dismissAccountMenu,\n  ]);\n\n  // Setup for navigation dropdown (label4): handles positioning and interactions\n  const {\n    context: label4FloatingContext,\n    floatingStyles: label4FloatingStyles,\n    refs: label4FloatingRefs,\n  } = useFloating({\n    middleware: [offset(2)],\n    open: label4Open,\n    onOpenChange: setLabel4Open,\n    placement: 'bottom-start',\n    whileElementsMounted: autoUpdate,\n  });\n  const clickLabel4Ref = useClick(label4FloatingContext);\n  const dismissLabel4Menu = useDismiss(label4FloatingContext);\n  const { getReferenceProps: getLabel4ReferenceProps, getFloatingProps: getLabel4FloatingProps } = useInteractions([\n    clickLabel4Ref,\n    dismissLabel4Menu,\n  ]);\n\n  // Toggles mobile navigation drawer open and closed\n  const onToggleMobileMenu = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  return (\n    <div>\n      <Link skipLink href=\"#content\" alternate>\n        Skip to content\n      </Link>\n      <UtilityFragment vJustifyContent=\"between\">\n        {/* Main navigation container with alternate styling */}\n        <Nav id={id} orientation=\"horizontal\" tag=\"header\" alternate>\n          {/* Default nav: logo, tabs, actions */}\n          {!expandSearch ? (\n            <>\n              {/* Mobile menu toggle button */}\n              <UtilityFragment vContainerHide=\"desktop\">\n                <DropdownButton\n                  aria-controls={`${id}-mobile-menu`}\n                  aria-expanded={mobileMenuOpen ? 'true' : 'false'}\n                  aria-label=\"open menu\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  id={`${id}-mobile-menu-button`}\n                  onClick={onToggleMobileMenu}\n                >\n                  {mobileMenuOpen ? (\n                    <VisaCloseTiny />\n                  ) : (\n                    <>\n                      <VisaMenuLow />\n                    </>\n                  )}\n                </DropdownButton>\n              </UtilityFragment>\n              {/* Logo and app name */}\n              <UtilityFragment vFlex vGap={16}>\n                <Link\n                  aria-label=\"Visa Application Name Home\"\n                  href=\"./application-layouts\"\n                  id={`${id}-home-link`}\n                  noUnderline\n                  style={{ backgroundColor: 'transparent' }}\n                >\n                  <VisaLogo />\n                  <UtilityFragment vContainerHide=\"mobile\">\n                    <NavAppName>\n                      <Utility\n                        vContainerHide=\"xs\"\n                        element={<Typography variant=\"headline-3\">Application name</Typography>}\n                      />\n                    </NavAppName>\n                  </UtilityFragment>\n                </Link>\n              </UtilityFragment>\n              {/* Desktop navigation tabs - hidden on mobile */}\n              <UtilityFragment vFlex vJustifyContent=\"end\" vFlexGrow vMarginLeft=\"auto\" vContainerHide=\"mobile\">\n                <nav aria-label=\"global\">\n                  <UtilityFragment vGap={4}>\n                    <Tabs>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 1</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 2</a>}\n                        />\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 3</a>}\n                        />\n                      </Tab>\n                      {/* Tab with dropdown submenu */}\n                      <Tab>\n                        <DropdownButton\n                          aria-expanded={label4Open}\n                          aria-controls={label4Open ? `${id}-label-dropdown-menu` : undefined}\n                          id={`${id}-label-dropdown-button`}\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          ref={label4FloatingRefs.setReference}\n                          {...getLabel4ReferenceProps()}\n                        >\n                          L1 label 4<TabSuffix element={label4Open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                        </DropdownButton>\n\n                        {label4Open && (\n                          <FloatingFocusManager\n                            context={label4FloatingContext}\n                            modal={false}\n                            initialFocus={-1}\n                            restoreFocus={true}\n                          >\n                            <DropdownMenu\n                              id={`${id}-label-dropdown-menu`}\n                              aria-hidden={!label4Open}\n                              style={\n                                {\n                                  inlineSize: '180px',\n                                  position: 'absolute',\n                                  ...label4FloatingStyles,\n                                  zIndex: 1,\n                                } as CSSProperties\n                              }\n                              ref={label4FloatingRefs.setFloating}\n                              {...getLabel4FloatingProps()}\n                            >\n                              <Listbox>\n                                {label4SubItems.map(label4SubItem => (\n                                  <li key={label4SubItem.id}>\n                                    <ListboxItem<'a'> href={label4SubItem.href} tag=\"a\">\n                                      {label4SubItem.tabLabel}\n                                    </ListboxItem>\n                                  </li>\n                                ))}\n                              </Listbox>\n                            </DropdownMenu>\n                          </FloatingFocusManager>\n                        )}\n                      </Tab>\n                      <Tab>\n                        <Button\n                          buttonSize=\"large\"\n                          colorScheme=\"tertiary\"\n                          element={<a href=\"./application-layouts\">L1 label 5</a>}\n                        />\n                      </Tab>\n                    </Tabs>\n                  </UtilityFragment>\n                </nav>\n              </UtilityFragment>\n              {/* Action buttons: search, notifications, account */}\n              <Utility vFlex vGap={8} vMarginLeft={8}>\n                <Button\n                  aria-label=\"search site\"\n                  ref={searchButtonRef}\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => {\n                    setExpandSearch(true);\n                    searchInitiallyActivated.current = true;\n                  }}\n                >\n                  <VisaSearchLow />\n                </Button>\n                {/* Notifications button with badge */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Button\n                    aria-label=\"notifications\"\n                    aria-describedby={`${id}-notifications-badge`}\n                    buttonSize=\"large\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                  >\n                    <VisaNotificationsLow />\n                    <Badge id={`${id}-notifications-badge`} badgeVariant=\"number\" tag=\"sup\">\n                      3\n                    </Badge>\n                  </Button>\n                </UtilityFragment>\n                {/* Account dropdown menu */}\n                <UtilityFragment vContainerHide=\"mobile\">\n                  <Tab tag=\"div\">\n                    <DropdownButton\n                      aria-expanded={accountMenuOpen}\n                      aria-controls={accountMenuOpen ? `${id}-account-menu` : undefined}\n                      aria-label=\"Alex Miller\"\n                      buttonSize=\"large\"\n                      colorScheme=\"tertiary\"\n                      element={<Avatar tag=\"button\" />}\n                      ref={accountFloatingRefs.setReference}\n                      {...getAccountReferenceProps()}\n                    >\n                      <VisaAccountLow />\n                      <TabSuffix element={accountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n                    </DropdownButton>\n                    {accountMenuOpen && (\n                      <FloatingFocusManager\n                        context={accountFloatingContext}\n                        modal={false}\n                        initialFocus={-1}\n                        restoreFocus={true}\n                      >\n                        <DropdownMenu\n                          id={`${id}-account-menu`}\n                          aria-hidden={!accountMenuOpen}\n                          style={\n                            {\n                              inlineSize: '180px',\n                              position: 'absolute',\n                              ...accountFloatingStyles,\n                              zIndex: 1,\n                            } as CSSProperties\n                          }\n                          ref={accountFloatingRefs.setFloating}\n                          {...getAccountFloatingProps()}\n                        >\n                          <Listbox>\n                            {accountSubItems.map(accountSubItem => (\n                              <UtilityFragment key={accountSubItem.id}>\n                                <li>\n                                  <ListboxItem<'a'> href={accountSubItem.href} tag=\"a\">\n                                    {accountSubItem.tabLabel}\n                                  </ListboxItem>\n                                </li>\n                              </UtilityFragment>\n                            ))}\n                          </Listbox>\n                        </DropdownMenu>\n                      </FloatingFocusManager>\n                    )}\n                  </Tab>\n                </UtilityFragment>\n              </Utility>\n            </>\n          ) : (\n            /* Expanded search replaces entire nav bar */\n            <UtilityFragment vFlex>\n              <Surface\n                style={\n                  {\n                    '--v-surface-background': 'var(--palette-default-surface-3)',\n                    '--v-surface-border-radius': 'var(--size-rounded-medium)',\n                    '--v-surface-padding-inline': 'var(--size-scalable-8)',\n                  } as CSSProperties\n                }\n              >\n                <InputContainer>\n                  <VisaSearchLow />\n                  <Input\n                    id={`${id}-search-field`}\n                    name={`${id}-search-field`}\n                    ref={searchInputRef}\n                    required\n                    type=\"search\"\n                    aria-label=\"Search\"\n                    placeholder=\"Search\"\n                  />\n                </InputContainer>\n                <Button\n                  aria-label=\"close search\"\n                  buttonSize=\"large\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  onClick={() => setExpandSearch(false)}\n                >\n                  <VisaCloseLow />\n                </Button>\n              </Surface>\n            </UtilityFragment>\n          )}\n        </Nav>\n      </UtilityFragment>\n      {/* Mobile navigation drawer with alternate styling */}\n      <UtilityFragment vContainerHide=\"desktop\" vHide={!mobileMenuOpen}>\n        <Nav\n          alternate\n          aria-label=\"global menu\"\n          aria-hidden={!mobileMenuOpen}\n          id={`${id}-mobile-menu`}\n          orientation=\"vertical\"\n        >\n          {/* Mobile nav items */}\n          <Tabs orientation=\"vertical\">\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 1</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 2</a>}\n              />\n            </Tab>\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                element={<a href=\"./application-layouts\">L1 label 3</a>}\n              />\n            </Tab>\n            {/* Tab with expandable submenu in mobile */}\n            <Tab>\n              <Button\n                aria-expanded={mobileLabel4MenuOpen}\n                aria-controls={mobileLabel4MenuOpen ? `${id}-account-sub-menu` : 'undefined'}\n                id={`${id}-mobile-menu-label-dropdown-button`}\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileLabel4MenuOpen(!mobileLabel4MenuOpen)}\n              >\n                L1 label 4\n                <TabSuffix element={mobileLabel4MenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n\n              {mobileLabel4MenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {label4SubItems.map(label4SubItem => (\n                    <Tab key={label4SubItem.id} id={label4SubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={label4SubItem.href}>{label4SubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n            {/* Notifications item (badge inline on mobile) */}\n            <Tab>\n              <Button\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                style={{ wordBreak: 'break-word', blockSize: 'max-content' } as CSSProperties}\n              >\n                Notifications\n                <Badge\n                  badgeVariant=\"number\"\n                  style={\n                    {\n                      position: 'relative',\n                    } as CSSProperties\n                  }\n                  tag=\"sup\"\n                >\n                  3\n                </Badge>\n              </Button>\n            </Tab>\n          </Tabs>\n          <UtilityFragment vMarginTop={5}>\n            <Divider dividerType=\"decorative\" />\n          </UtilityFragment>\n          {/* Account section at bottom of mobile menu */}\n          <UtilityFragment vMarginTop={6} className=\"v-tabs-vertical\">\n            <Tab tag=\"div\">\n              <Button\n                aria-expanded={mobileAccountMenuOpen}\n                aria-controls={`${id}-account-sub-menu`}\n                aria-label=\"Alex Miller\"\n                buttonSize=\"large\"\n                colorScheme=\"tertiary\"\n                onClick={() => setMobileAccountMenuOpen(!mobileAccountMenuOpen)}\n              >\n                <VisaAccountLow />\n                Alex Miller\n                <TabSuffix element={mobileAccountMenuOpen ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />} />\n              </Button>\n              {mobileAccountMenuOpen && (\n                <Tabs orientation=\"vertical\" id={`${id}-account-sub-menu`}>\n                  {accountSubItems.map(accountSubItem => (\n                    <Tab key={accountSubItem.id} id={accountSubItem.id}>\n                      <Button\n                        colorScheme=\"tertiary\"\n                        element={<a href={accountSubItem.href}>{accountSubItem.tabLabel}</a>}\n                      />\n                    </Tab>\n                  ))}\n                </Tabs>\n              )}\n            </Tab>\n          </UtilityFragment>\n        </Nav>\n      </UtilityFragment>\n    </div>\n  );\n};\n"
          },
          "name": "Alternate horizontal nav"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Mixed application layouts",
          "url": {
            "iframe": "patterns/application-layouts/vertical-mixed-nav-layout",
            "github": "apps/workshop/src/examples/patterns/application-layouts/vertical-mixed-nav-layout.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/vertical-mixed-nav-layout.tsx": "import {\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n  VisaNotesTiny,\n  VisaSecurityTiny,\n  VisaSettingsTiny,\n  VisaStatisticsTiny,\n  VisaSupportTicketTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Divider, Nav, Tab, Tabs, Utility, UtilityFragment } from '@visa/nova-react';\nimport { useState } from 'react';\n\n// Base ID for aria attributes and element IDs - customize for unique identification\nconst id = 'vertical-mixed-navigation';\n\n// Secondary (L2) navigation tab items with icons - customize labels, icons, and hrefs\nconst tabsContent = [\n  {\n    tabLabel: 'L2 label 1',\n    id: `${id}-tab-0`,\n    icon: <VisaStatisticsTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L2 label 2',\n    id: `${id}-tab-1`,\n    icon: <VisaSettingsTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L2 label 3',\n    id: `${id}-tab-2`,\n    icon: <VisaSecurityTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L2 label 4',\n    id: `${id}-tab-3`,\n    icon: <VisaNotesTiny />,\n    href: './application-layouts',\n  },\n  {\n    tabLabel: 'L2 label 5',\n    id: `${id}-tab-4`,\n    icon: <VisaSupportTicketTiny />,\n    href: './application-layouts',\n  },\n];\n\n/**\n * Left sidebar navigation component used by MixedApplicationLayout.\n */\nexport const VerticalMixedNavLayout = () => {\n  // Controls whether sidebar is expanded (with labels) or collapsed (icons only)\n  const [navExpanded, setNavExpanded] = useState(true);\n\n  return (\n    <Nav id={id} orientation=\"vertical\" className=\"layout-vertical-mixed\" aria-label=\"primary\">\n      {/* L2 navigation tabs - hidden when collapsed */}\n      {navExpanded && (\n        <>\n          <Utility className=\"mixed-vertical-tabs\" vAlignSelf=\"stretch\">\n            <UtilityFragment vGap={8}>\n              <Tabs orientation=\"vertical\">\n                {tabsContent.map(tabContent => (\n                  <Tab key={tabContent.id}>\n                    <Button\n                      colorScheme=\"tertiary\"\n                      element={\n                        <a href=\"./application-layouts\">\n                          {tabContent.icon}\n                          {tabContent.tabLabel}\n                        </a>\n                      }\n                    />\n                  </Tab>\n                ))}\n              </Tabs>\n            </UtilityFragment>\n          </Utility>\n        </>\n      )}\n      {/* Footer section: collapse toggle only (no account menu in mixed layout) */}\n      <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={4} vMarginTop=\"auto\">\n        <UtilityFragment vMarginBottom={4}>\n          <Divider dividerType=\"decorative\" />\n        </UtilityFragment>\n        {/* Collapse/expand toggle button */}\n        <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n          <Button\n            aria-label=\"Side bar\"\n            aria-expanded={!!navExpanded}\n            buttonSize=\"small\"\n            colorScheme=\"tertiary\"\n            iconButton\n            onClick={() => setNavExpanded(!navExpanded)}\n            subtle\n          >\n            {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n          </Button>\n        </UtilityFragment>\n      </Utility>\n    </Nav>\n  );\n};\n"
          },
          "name": "Vertical mixed nav"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Mixed application layouts",
          "url": {
            "iframe": "patterns/application-layouts/styles-mixed",
            "github": "apps/workshop/src/examples/patterns/application-layouts/styles-mixed.css"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/application-layouts/styles-mixed.css": "/* Layout with header spanning full width, sidebar on left, and content on right */\n.layout-mixed {\n  display: grid;\n  grid-template-columns: auto 1fr;\n  grid-template-rows: auto 1fr;\n  grid-template-areas: 'header header' 'nav content';\n  height: 100vh;\n  background-color: var(--palette-default-surface-3, #f0f0f0);\n}\n\n/* When sidebar navigation is expanded, set fixed width for consistent spacing */\n.layout-mixed:has(.mixed-vertical-tabs) {\n  grid-template-columns: 242px 1fr !important;\n}\n\n/* Higher z-index keeps header above other elements when scrolling */\n.layout-mixed .layout-header {\n  z-index: 3;\n  position: relative;\n  grid-area: header;\n}\n\n.layout-mixed .layout-vertical-mixed {\n  grid-area: nav;\n}\n\n/* Allows content area to scroll independently while header and sidebar stay fixed */\n.layout-mixed .layout-content {\n  position: relative;\n  overflow-y: auto;\n  display: flex;\n  flex-direction: column;\n  grid-area: content;\n}\n\n/* Main content grows to fill available space, pushing footer to bottom */\n.layout-mixed main {\n  display: block;\n  flex-grow: 1;\n}\n\n/* Match footer background to overall page background */\n.layout-mixed footer {\n  --v-footer-background-color: var(--v-palette-default-surface-3);\n}\n\n/* Show/hide elements based on screen size for mobile and desktop views */\n@container (max-width: 1003px) {\n  .layout-mixed .v-mobile-container-hide {\n    display: none;\n  }\n\n  .layout-mixed .v-desktop-container-hide {\n    display: block;\n  }\n\n  .layout-mixed .v-desktop-container-hide.v-hide {\n    display: none;\n  }\n}\n\n@container (min-width: 1004px) {\n  .layout-mixed .v-mobile-container-hide {\n    display: flex;\n  }\n\n  .layout-mixed .v-desktop-container-hide {\n    display: none;\n  }\n}\n"
          },
          "name": "Styles mixed"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/application-layouts/footer-layout.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/application-layouts/shared/footer-layout.tsx": "import { Footer, Link, Utility, VisaLogo } from '@visa/nova-react';\n\n/**\n * Shared footer component used by all application layouts.\n */\nexport const FooterLayout = () => {\n  return (\n    <Footer className=\"v-gap-15\">\n      {/* Visa logo */}\n      <Utility vFlex vMarginRight={1}>\n        <VisaLogo aria-label=\"Visa\" />\n      </Utility>\n      {/* Copyright text and footer links */}\n      <Utility vFlex vFlexWrap vFlexGrow vJustifyContent=\"between\" vGap={42}>\n        {`Copyright © ${new Date().getFullYear()} Visa Inc. All Rights Reserved`}\n        {/* Footer navigation links - customize as needed */}\n        <Utility tag=\"ul\" vFlex vFlexWrap vGap={16}>\n          <li>\n            <Link href=\"./application-layouts\">Contact us</Link>\n          </li>\n          <li>\n            <Link href=\"./application-layouts\">Privacy</Link>\n          </li>\n          <li>\n            <Link href=\"./application-layouts\">Terms of use</Link>\n          </li>\n        </Utility>\n      </Utility>\n    </Footer>\n  );\n};\n"
          },
          "name": "Footer layout"
        }
      ],
      "propertySections": [],
      "properties": []
    },
    {
      "name": "chat",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "patterns",
      "exampleSections": [
        {
          "name": "Full-page chat",
          "description": "",
          "order": 1
        },
        {
          "name": "Dialog chat",
          "description": "",
          "order": 2
        },
        {
          "name": "Panel chat",
          "description": "",
          "order": 3
        },
        {
          "name": "Shared Components",
          "description": "",
          "order": 4
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Full-page chat",
          "url": {
            "iframe": "patterns/chat/default-full-page-chat",
            "github": "apps/workshop/src/examples/patterns/chat/default-full-page-chat.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/chat/default-full-page-chat.tsx": "import { default as FullPageNavigation } from \"./full-page-navigation\";\nimport { default as FullPageChatCard } from \"./full-page-chat-card\";\nimport \"./full-page-css.scss\";\nimport ChatProvider from \"./shared/chat-provider\";\nimport { useEffect, useState } from \"react\";\n\n// Base ID for aria attributes - customize to ensure uniqueness\nconst id = 'full-page-chat';\n\n/**\n * Full-page chat application with collapsible sidebar navigation and main chat area.\n * Wraps components in ChatProvider for shared state management between chat history navigation and active conversation.\n */\nconst DefaultFullPageChat = () => {\n  // Tracks viewport size to enable responsive layout adjustments\n  const [isSmallScreen, setIsSmallScreen] = useState(false);\n\n  // Monitor viewport width and update isSmallScreen state\n  // Triggers responsive behavior for navigation collapse and avatar sizing\n  useEffect(() => {\n    const checkScreenSize = () => {\n      setIsSmallScreen(window.innerWidth <= 500);\n    };\n\n    checkScreenSize();\n    window.addEventListener('resize', checkScreenSize);\n    return () => window.removeEventListener('resize', checkScreenSize);\n  }, []);\n\n  return (\n    <ChatProvider>\n      <div id={id} className=\"layout-example app-container\">\n        <div className=\"layout-container\">\n          {/* Collapsible sidebar with chat history and search */}\n          <FullPageNavigation isSmallScreen={isSmallScreen} />\n          {/* Main content area with active chat */}\n          <main id={`${id}-content`} className=\"main-content\">\n            <FullPageChatCard smallAvatar={isSmallScreen} />\n          </main>\n        </div>\n      </div>\n    </ChatProvider>\n  );\n};\n\nexport default DefaultFullPageChat;\n"
          },
          "name": "Default full page chat"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Full-page chat",
          "url": {
            "iframe": "patterns/chat/full-page-chat-card",
            "github": "apps/workshop/src/examples/patterns/chat/full-page-chat-card.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/chat/full-page-chat-card.tsx": "import {\n  VisaDeleteTiny,\n  VisaEditTiny,\n  VisaFileDownloadTiny,\n  VisaIdeaTiny,\n  VisaOptionHorizontalTiny,\n  VisaPinOutlineTiny,\n  VisaSearchTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  ContentCard,\n  ContentCardBody,\n  DropdownButton,\n  DropdownMenu,\n  Listbox,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { default as ChatInput } from './shared/chat-input';\nimport { default as ChatSuggestions } from './shared/chat-suggestions';\nimport { useContext, useEffect, useState } from 'react';\nimport ChatContext from './shared/chat-context';\nimport UserChatBubble from './shared/user-chat-bubble';\nimport ResponseChatBubble from './shared/response-chat-bubble';\nimport { useFloating, useClick, useInteractions } from '@floating-ui/react';\n\n// Base ID for aria attributes - customize to ensure uniqueness\nconst id = 'full-page-chat-card';\n\n/**\n * Props for the FullPageChatCard component\n *\n * @property smallAvatar - (optional) Use smaller avatar variant for chat bubbles with small screens\n */\ntype FullPageChatCardProps = {\n  smallAvatar?: boolean;\n};\n\n/**\n * Main chat content card with welcome screen, scrollable message history, and input field.\n * Uses ChatContext to share conversation state with navigation sidebar and includes mock auto-response logic for demonstration.\n */\nconst FullPageChatCard = ({ smallAvatar }: FullPageChatCardProps) => {\n  // Floating UI for header actions dropdown\n  const [open, setOpen] = useState(false);\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-end',\n  });\n\n  const onFloatingClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onFloatingClick]);\n\n  // Access shared chat state from context\n  const { responses, setResponses } = useContext(ChatContext);\n\n  // Mock auto-response after user message\n  // IMPORTANT: This response format assumes code blocks wrapped in three tildes + language (e.g., ~~~js).\n  // Adjust to match your syntax highlighter and API response format.\n  useEffect(() => {\n    if (responses.length > 0) {\n      responses[responses.length - 1].role === 'User 2'\n        ? ''\n        : setResponses([\n            ...responses,\n            {\n              message: `Here is the code for the default horizontal navigation from VPDS Nova CSS:`,\n              code: `\n <header class=\"v-nav v-nav-horizontal v-alternate v-icon-two-color v-justify-content-between\">\n <button aria-label=\"open menu\" class=\"v-button v-button-icon v-button-tertiary v-button-large v-desktop-container-hide\" type=\"button\">\n <VisaMenuLow />\n </button>\n </header> `,\n              timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n              role: 'User 2',\n            },\n          ]);\n    }\n  }, [responses]);\n\n  return (\n    <ContentCard id={id} style={{ minBlockSize: 'calc(100vh - 64px)', containerType: 'inline-size', minInlineSize: '300px' }} >\n      <Utility\n        vPaddingHorizontal={20}\n        vFlex\n        vJustifyContent=\"between\"\n        vAlignItems=\"center\"\n        style={{\n          blockSize: '56px',\n          borderBlockEnd: 'var(--v-content-card-border)',\n          boxShadow: 'var(--v-content-card-elevation),var(--v-content-card-border-block-end-none)',\n        }}\n      >\n        <span>Chat name</span>\n        <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={10}>\n          <Button aria-label=\"pin\" colorScheme=\"tertiary\" iconButton subtle>\n            <VisaPinOutlineTiny />\n          </Button>\n          <DropdownButton\n            buttonSize=\"small\"\n            aria-controls={`${id}-more-options`}\n            aria-expanded={open}\n            aria-label=\"see more options\"\n            iconButton\n            colorScheme=\"tertiary\"\n            subtle\n            id={`${id}-more-options-button`}\n            ref={refs.setReference}\n            {...getReferenceProps({\n              onBlur: () => setOpen(false),\n            })}\n          >\n            <VisaOptionHorizontalTiny />\n          </DropdownButton>\n          {open && (\n            <DropdownMenu\n              id={`${id}-more-options`}\n              aria-hidden={!open}\n              ref={refs.setFloating}\n              style={{ inlineSize: '180px', zIndex: 1000, ...floatingStyles }}\n              {...getFloatingProps()}\n            >\n              <UtilityFragment vHide={!open}>\n                <Listbox>\n                  <li>\n                    <UtilityFragment\n                      vFlex\n                      vFlexRow\n                      vAlignItems=\"start\"\n                      vGap={6}\n                      vPaddingHorizontal={8}\n                      vPaddingVertical={11}\n                    >\n                      <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                        <VisaEditTiny /> Rename\n                      </Button>\n                    </UtilityFragment>\n                  </li>\n                  <li>\n                    <UtilityFragment\n                      vFlex\n                      vFlexRow\n                      vAlignItems=\"start\"\n                      vGap={6}\n                      vPaddingHorizontal={8}\n                      vPaddingVertical={11}\n                    >\n                      <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                        <VisaSearchTiny /> Search in chat\n                      </Button>\n                    </UtilityFragment>\n                  </li>\n                  <li>\n                    <UtilityFragment\n                      vFlex\n                      vFlexRow\n                      vAlignItems=\"start\"\n                      vGap={6}\n                      vPaddingHorizontal={8}\n                      vPaddingVertical={11}\n                    >\n                      <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                        <VisaFileDownloadTiny /> Download\n                      </Button>\n                    </UtilityFragment>\n                  </li>\n                  <li>\n                    <UtilityFragment\n                      vFlex\n                      vFlexRow\n                      vAlignItems=\"start\"\n                      vGap={6}\n                      vPaddingHorizontal={8}\n                      vPaddingVertical={11}\n                    >\n                      <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                        <VisaIdeaTiny /> Make a suggestion\n                      </Button>\n                    </UtilityFragment>\n                  </li>\n                  <li>\n                    <UtilityFragment\n                      vFlex\n                      vFlexRow\n                      vAlignItems=\"start\"\n                      vGap={6}\n                      vPaddingHorizontal={8}\n                      vPaddingVertical={11}\n                    >\n                      <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" destructive>\n                        <VisaDeleteTiny /> Delete chat\n                      </Button>\n                    </UtilityFragment>\n                  </li>\n                </Listbox>\n              </UtilityFragment>\n            </DropdownMenu>\n          )}\n        </Utility>\n      </Utility>\n      {/* Card body with welcome screen or message history */}\n      <Utility\n        element={<ContentCardBody />}\n        vFlex\n        vFlexCol\n        vJustifyContent=\"between\"\n        style={{\n          blockSize: 'calc(100vh - 120px)',\n          minBlockSize: 'fit-content',\n          padding: 24,\n        }}\n      >\n        {/* Show welcome message when no conversation yet */}\n        {responses.length === 0 ? (\n          <Utility vFlex vFlexCol>\n            <Typography variant=\"headline-3\">Welcome!</Typography>\n            <Typography className=\"v-pt-4\">\n              I&apos;m your friendly AI chatbot, here to assist you. I&apos;m powered by artificial intelligence, which\n              allows me to learn and adapt to better serve your needs. Our conversations are stored to improve our\n              services, but you have the right to access, correct, or delete your personal information at any time.\n            </Typography>\n          </Utility>\n        ) : (\n          /* Scrollable message history */\n          <Utility\n            vFlex\n            vFlexCol\n            vGap={24}\n            style={{\n              flex: 1,\n              overflowY: 'auto',\n            }}\n          >\n            {responses.map((response, index) => {\n              // Show timestamp only on first message or when role changes\n              const prev = responses[index - 1];\n              const hideTimestamp = index !== 0 && response.role === prev?.role;\n\n              return (\n                response.role === \"User 1\" ? (\n                  <UserChatBubble key={`${id}-user-${index}`} id={`${id}-user-${index}`} response={response} hideTimestamp={hideTimestamp} smallAvatar={smallAvatar} />\n                ) : (\n                  <ResponseChatBubble key={`${id}-response-${index}`} id={`${id}-response-${index}`} response={response} hideTimestamp={hideTimestamp} smallAvatar={smallAvatar} />\n                )\n              )\n            })}\n          </Utility>\n        )}\n        {/* Input section - shows suggestions when empty */}\n        <Utility vFlex vFlexCol vGap={8}>\n          {responses.length === 0 && <ChatSuggestions />}\n          <ChatInput id={`${id}-input`} />\n        </Utility>\n      </Utility>\n    </ContentCard>\n  );\n};\n\nexport default FullPageChatCard;\n"
          },
          "name": "Full page chat card"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Full-page chat",
          "url": {
            "iframe": "patterns/chat/full-page-css",
            "github": "apps/workshop/src/examples/patterns/chat/full-page-css.scss"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/chat/full-page-css.scss": ".app-container {\n  container-type: inline-size;\n\n  @container (max-width: 600px) {\n    .layout-container {\n      // Fallback to a single column.\n      // This forces reflow on small devices.\n      grid-template-columns: 1fr;\n    }\n  }\n}\n\n.layout-container {\n  min-block-size: 700px;\n  display: grid;\n  grid-template-columns: auto 1fr;\n}\n\n.main-content {\n  background-color: var(--palette-default-surface-3);\n  min-block-size: 500px;\n  padding: 32px;\n  overflow-x: auto;\n  overflow-x: auto;\n}"
          },
          "name": "Full page css"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Full-page chat",
          "url": {
            "iframe": "patterns/chat/full-page-navigation",
            "github": "apps/workshop/src/examples/patterns/chat/full-page-navigation.tsx"
          },
          "tags": [
            "patterns",
            "isSubComponent"
          ],
          "snippets": {
            "patterns/chat/full-page-navigation.tsx": "import {\n  VisaAddAltTiny,\n  VisaMediaFastForwardTiny,\n  VisaMediaRewindTiny,\n  VisaPinFillTiny,\n  VisaSearchLow,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  Divider,\n  Input,\n  InputContainer,\n  Link,\n  Nav,\n  NavAppName,\n  Tab,\n  Tabs,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from \"@visa/nova-react\";\nimport { useContext, useEffect, useState } from \"react\";\nimport ChatContext from \"./shared/chat-context\";\nimport \"./full-page-navigation-css.scss\";\n\n// Base ID for aria attributes and element IDs\nconst id = 'full-page-vertical-navigation';\n\n/**\n * Props for the FullPageNavigation component\n *\n * @property isSmallScreen - (optional) Collapses navigation to icon-only mode for smaller viewports\n */\ntype FullPageNavigationProps = {\n  isSmallScreen?: boolean;\n};\n\n/**\n * Collapsible sidebar navigation for full-page chat with search input, organized chat history, and new chat action.\n * Uses ChatContext to manage conversation state and organizes chat history by time periods (pinned, recent, older).\n*/\nconst FullPageNavigation = ({ isSmallScreen }: FullPageNavigationProps) => {\n  const { setResponses } = useContext(ChatContext);\n\n  // Controls whether sidebar shows labels or icons only\n  const [navExpanded, setNavExpanded] = useState(true);\n\n  useEffect(() => {\n    setNavExpanded(!isSmallScreen);\n  }, [isSmallScreen]);\n\n  // Clears current conversation and starts fresh\n  const startNewChat = () => {\n    setResponses([]);\n  };\n\n  return (\n    <Nav id={id} orientation=\"vertical\" tag=\"header\" className=\"full-page-nav\" style={{ blockSize: 'auto' }}>\n      {/* Skip link only shown when expanded */}\n      {navExpanded && (\n        <Link skipLink href=\"#full-page-content\">\n          Skip to content\n        </Link>\n      )}\n      {/* Logo, search, and chat history - hidden when collapsed */}\n      {navExpanded ? (\n        <>\n          <UtilityFragment\n            vFlex\n            vFlexCol\n            vGap={12}\n            vMarginTop={16}\n            vMarginRight={16}\n            vMarginBottom={30}\n            vMarginLeft={20}\n          >\n            <Link\n              aria-label=\"application name\"\n              href=\"https://www.visa.com\"\n              id={`${id}-home-link`}\n              noUnderline\n              style={{ backgroundColor: 'transparent' }}\n            >\n              <NavAppName>\n                <Typography variant=\"subtitle-1\">Application name</Typography>\n              </NavAppName>\n            </Link>\n          </UtilityFragment>\n\n          {/* Search input - implement search logic as needed */}\n          <Utility vMarginHorizontal={24} vMarginBottom={24}>\n            <Utility vFlex vFlexCol vGap={4}>\n              <InputContainer>\n                <Utility vFlex vFlexCol>\n                  <VisaSearchLow />\n                </Utility>\n                <Input aria-required=\"true\" id={`${id}-search-input`} type=\"text\" placeholder=\"Search\" />\n              </InputContainer>\n            </Utility>\n          </Utility>\n\n          {/* Chat history organized by time sections */}\n          <nav aria-label=\"default vertical navigation\">\n            <Utility vGap={8}>\n              <Tabs orientation=\"vertical\">\n                <Tab sectionTitle>Pinned chats</Tab>\n                <Tab>\n                  <Button\n                    colorScheme=\"tertiary\"\n                    element={\n                      <a href=\"./chat\">\n                        <VisaPinFillTiny />\n                        Chat name 1\n                      </a>\n                    }\n                  ></Button>\n                </Tab>\n                <Tab sectionTitle>2 days ago</Tab>\n                {['Chat name 1', 'Chat name 2', 'Chat name 3'].map((chatName, index) => (\n                  <Tab key={`2-days-history-${index}`}>\n                    <Button colorScheme=\"tertiary\" element={<a href=\"./chat\">{chatName}</a>} />\n                  </Tab>\n                ))}\n\n                <Tab sectionTitle>1 week ago</Tab>\n                {['Chat name 4', 'Chat name 5', 'Chat name 6'].map((chatName, index) => (\n                  <Tab key={`1-week-history-${index}`}>\n                    <Button colorScheme=\"tertiary\" element={<a href=\"./chat\">{chatName}</a>} />\n                  </Tab>\n                ))}\n              </Tabs>\n            </Utility>\n          </nav>\n          {/* Footer section with new chat button */}\n          <Utility vFlex vFlexCol vAlignSelf=\"stretch\" vGap={30} vMarginTop=\"auto\">\n            <Divider dividerType=\"decorative\" />\n            <Utility vAlignSelf=\"center\" vGap={16} vMarginBottom={4}>\n              <Button\n                colorScheme=\"secondary\"\n                aria-label=\"start new chat\"\n                onClick={() => {\n                  startNewChat();\n                }}\n              >\n                <VisaAddAltTiny />\n                Start new chat\n              </Button>\n            </Utility>\n          </Utility>\n        </>\n      ) : (\n        <div style={{ flex: 1 }} />\n      )}\n      {/* Collapse/expand toggle button */}\n      <UtilityFragment vMarginLeft={navExpanded ? 'auto' : 5} vMarginRight={navExpanded ? 8 : 5}>\n        <Button\n          aria-label=\"Side bar\"\n          aria-expanded={!!navExpanded}\n          buttonSize=\"small\"\n          colorScheme=\"tertiary\"\n          iconButton\n          onClick={() => setNavExpanded(!navExpanded)}\n          subtle\n        >\n          {navExpanded ? <VisaMediaRewindTiny rtl /> : <VisaMediaFastForwardTiny rtl />}\n        </Button>\n      </UtilityFragment>\n    </Nav>\n  );\n};\n\nexport default FullPageNavigation;\n"
          },
          "name": "Full page navigation"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Dialog chat",
          "url": {
            "iframe": "patterns/chat/default-dialog-chat",
            "github": "apps/workshop/src/examples/patterns/chat/default-dialog-chat.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/chat/default-dialog-chat.tsx": "import { Button, Dialog, DialogContent, Typography, useFocusTrap, Utility } from '@visa/nova-react';\nimport { default as ChatInput } from './shared/chat-input';\nimport { VisaCloseLow, VisaMinimizeLow } from '@visa/nova-icons-react';\nimport ChatSuggestions from './shared/chat-suggestions';\nimport ResponseChatBubble from './shared/response-chat-bubble';\nimport UserChatBubble from './shared/user-chat-bubble';\n\n// Base ID for aria attributes - customize to ensure uniqueness\nconst id = 'modal-chatbot';\nconst BASE_URL = import.meta.env.BASE_URL;\n\n/**\n * Modal dialog chat interface.\n * Opens via button trigger and includes focus trap for keyboard accessibility and scrollable message history.\n */\nconst DefaultDialogChat = () => {\n  // useFocusTrap ensures keyboard navigation stays within dialog when open\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  // Mock conversation data - replace with actual chat state management\n  const responses = [\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message: 'This is a sent message.',\n      role: 'User 1',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message:\n        'This is a sent message with more text. It fills the container to a maximum width, then wraps to another line.',\n      role: 'User 1',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message: 'This is a received message.',\n      role: 'User 2',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message:\n        'This is a received message with more text. It fills the container to a maximum width, then wraps to another line.',\n      role: 'User 2',\n    },\n  ];\n\n  // Close dialog and return focus to trigger button\n  const handleClose = () => {\n    ref.current?.close();\n  };\n  return (\n    <div>\n      {/* Trigger button to open chat dialog */}\n\n      <Button aria-label=\"open chat\" iconButton onClick={() => ref.current?.showModal()}>\n        <img className=\"v-icon\" role=\"presentation\" src={`${BASE_URL}/chat-ai.svg`} />\n      </Button>\n\n      {/* Modal dialog container with focus trap */}\n      <Dialog\n        style={{\n          position: \"fixed\",\n          top: \"50%\",\n          left: \"50%\",\n          transform: \"translate(-50%, -50%)\",\n          inlineSize: \"500px\",\n          blockSize: \"min(500px, 90vh)\",\n          margin: \"0\",\n          padding: \"0\",\n          gap: \"10px\",\n          overflowX: \"auto\",\n          flexDirection: \"column\"\n        }}\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        id={id}\n        ref={ref}\n        onKeyDown={(e) => onKeyNavigation(e, ref.current?.open)}\n      >\n        {/* Dialog header with minimize and close actions */}\n        <Utility\n          vFlex\n          vJustifyContent=\"between\"\n          vAlignItems=\"center\"\n          style={{\n            blockSize: \"62px\",\n            borderRadius: '10px',\n            inlineSize: \"100%\",\n            minInlineSize: \"300px\",\n            paddingBlock: \"8px\",\n            paddingInline: \"16px\",\n            flexShrink: 0,\n            background: `var(--palette-default-surface-1, #FFF)`,\n            boxShadow: `0px 1px 3px 0px rgba(0, 0, 0, 0.05)`,\n          }}\n        >\n          <Button aria-label=\"minimize dialog\" colorScheme=\"tertiary\" iconButton buttonSize=\"large\" onClick={handleClose}>\n            <VisaMinimizeLow />\n          </Button>\n          <Typography variant=\"headline-3\" style={{ color: 'var(--palette-accent-app-name)' }}>Chat name</Typography>\n          <Button\n            aria-label=\"close dialog\"\n            colorScheme=\"tertiary\"\n            iconButton\n            buttonSize=\"large\"\n            onClick={handleClose}\n          >\n            <VisaCloseLow />\n          </Button>\n        </Utility>\n        {/* Scrollable chat history container */}\n\n        <Utility\n          vFlex\n          vFlexCol\n          style={{\n            flex: \"1\",\n            blockSize: \"500px\",\n            minInlineSize: \"300px\",\n            overflow: \"auto\",\n            padding: \"var(--size-scalable-16)\"\n          }\n          }\n        >\n          <DialogContent>\n            {responses.map((response, index) => {\n              // Show timestamp only on first message or when role changes\n              const prev = responses[index - 1];\n              const hideTimestamp = index !== 0 && response.role === prev?.role;\n\n              return (\n                response.role === \"User 1\" ? (\n                  <UserChatBubble key={`${id}-user-${index}`} id={`${id}-user-${index}`} response={response} hideAvatar={true} hideTimestamp={hideTimestamp} />\n                ) : (\n                  <div key={`${id}-response-${index}`} style={{ marginInlineEnd: 48 }}>\n                    <ResponseChatBubble id={`${id}-response-${index}`} smallAvatar={true} response={response} hideTimestamp={hideTimestamp} />\n                  </div>))\n            })}\n          </DialogContent>\n        </Utility>\n        {/* Input section at bottom - shows suggestions when no messages */}\n        <Utility vFlex vFlexCol vGap={8} vPadding={16} style={{\n          overflow: 'auto',\n          flexShrink: 0,\n          minInlineSize: \"300px\"\n        }}>\n          {responses.length === 0 && <ChatSuggestions />}\n          <ChatInput id={`${id}-input`} showCharacterCount={false} style={{\n            borderRadius: \"10px\",\n          }} />\n        </Utility>\n      </Dialog>\n    </div >\n  );\n};\n\nexport default DefaultDialogChat;\n"
          },
          "name": "Default dialog chat"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Panel chat",
          "url": {
            "iframe": "patterns/chat/default-panel-chat",
            "github": "apps/workshop/src/examples/patterns/chat/default-panel-chat.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/chat/default-panel-chat.tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport {\n  VisaDeleteTiny,\n  VisaEditTiny,\n  VisaFileDownloadTiny,\n  VisaIdeaTiny,\n  VisaOptionHorizontalTiny,\n  VisaSearchTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  DropdownButton,\n  DropdownMenu,\n  Listbox,\n  Panel,\n  PanelBody,\n  PanelContent,\n  PanelToggle,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useState } from 'react';\nimport { default as ChatInput } from './shared/chat-input';\nimport ResponseChatBubble from './shared/response-chat-bubble';\nimport UserChatBubble from './shared/user-chat-bubble';\n\n// Base ID for aria attributes - customize to ensure uniqueness\nconst id = 'panel-chat';\n\n/**\n * Responsive panel chat interface that opens from the right side with toggleable visibility.\n */\nconst DefaultPanelChat = () => {\n  const BASE_URL = import.meta.env.BASE_URL;\n\n  // Controls panel open/close state\n  const [open, setOpen] = useState(false);\n\n  // Floating UI for header actions dropdown\n  const [dropdownOpen, setDropdownOpen] = useState(false);\n  const { context, floatingStyles, refs } = useFloating({\n    open: dropdownOpen,\n    onOpenChange: setDropdownOpen,\n    placement: 'bottom-end',\n  });\n\n  const onFloatingClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onFloatingClick]);\n\n  // Mock conversation data - replace with actual chat state management\n  const responses = [\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message: 'This is a sent message.',\n      role: 'User 1',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message:\n        'This is a sent message with more text. It fills the container to a maximum width, then wraps to another line.',\n      role: 'User 1',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message: 'This is a received message.',\n      role: 'User 2',\n    },\n    {\n      timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n      message:\n        'This is a received message with more text. It fills the container to a maximum width, then wraps to another line.',\n      role: 'User 2',\n    },\n  ];\n\n  return (\n    <div className=\"chat-example\" style={{ background: \"var(--palette-default-surface-3)\", overflow: \"auto\" }}>\n      <Utility vFlex style={{ blockSize: \"100vh\" }}>\n        {/* Toggle button positioned at top right */}\n        <Utility vMarginLeft=\"auto\">\n          <PanelToggle\n            aria-expanded={open}\n            aria-label={open ? 'Close panel' : 'Open panel'}\n            buttonSize=\"large\"\n            iconButton\n            iconTwoColor\n            onClick={() => setOpen(open ? false : true)}\n          >\n            <img role=\"presentation\"\n              src={`${BASE_URL}/chat-ai.svg`} />\n          </PanelToggle >\n        </Utility >\n\n        {/* Panel slides in from right when open */}\n        {\n          open && (\n            <Panel expandable style={{ inlineSize: \"400px\", minInlineSize: \"300px\" }}>\n              <PanelContent style={{ display: \"flex\", flexDirection: \"column\", blockSize: \"100%\", overflow: \"hidden\" }}>\n                {/* Panel header with chat name and actions menu */}\n                <Utility\n                  vFlex\n                  vJustifyContent=\"between\"\n                  vAlignItems=\"center\"\n                  style={{\n                    blockSize: '62px',\n                    inlineSize: '100%',\n                    paddingBlock: '8px',\n                    paddingInline: '16px',\n                    background: `var(--palette-default-surface-1, #FFF)`,\n                    boxShadow: `0px 1px 3px 0px rgba(0, 0, 0, 0.05)`,\n                    flexShrink: 0,\n                  }}\n                >\n                  {/* Empty spacer to balance the dropdown button */}\n                  <div style={{ inlineSize: 46 }} />\n                  <span>Chat name</span>\n                  <DropdownButton\n                    buttonSize=\"large\"\n                    aria-controls={`${id}-more-options`}\n                    aria-expanded={dropdownOpen}\n                    aria-label=\"see more options\"\n                    iconButton\n                    colorScheme=\"tertiary\"\n                    id={`${id}-more-options-button`}\n                    ref={refs.setReference}\n                    {...getReferenceProps({\n                      onBlur: () => setDropdownOpen(false),\n                    })}\n                  >\n                    <VisaOptionHorizontalTiny />\n                  </DropdownButton>\n                  {dropdownOpen && (\n                    <DropdownMenu\n                      id={`${id}-more-options`}\n                      aria-hidden={!dropdownOpen}\n                      ref={refs.setFloating}\n                      style={{ inlineSize: '180px', zIndex: 9999, ...floatingStyles }}\n                      {...getFloatingProps()}\n                    >\n                      <UtilityFragment vHide={!dropdownOpen}>\n                        <Listbox>\n                          <li>\n                            <UtilityFragment\n                              vFlex\n                              vFlexRow\n                              vAlignItems=\"start\"\n                              vGap={6}\n                              vPaddingHorizontal={8}\n                              vPaddingVertical={11}\n                            >\n                              <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                                <VisaEditTiny /> Rename\n                              </Button>\n                            </UtilityFragment>\n                          </li>\n                          <li>\n                            <UtilityFragment\n                              vFlex\n                              vFlexRow\n                              vAlignItems=\"start\"\n                              vGap={6}\n                              vPaddingHorizontal={8}\n                              vPaddingVertical={11}\n                            >\n                              <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                                <VisaSearchTiny /> Search in chat\n                              </Button>\n                            </UtilityFragment>\n                          </li>\n                          <li>\n                            <UtilityFragment\n                              vFlex\n                              vFlexRow\n                              vAlignItems=\"start\"\n                              vGap={6}\n                              vPaddingHorizontal={8}\n                              vPaddingVertical={11}\n                            >\n                              <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                                <VisaFileDownloadTiny /> Download\n                              </Button>\n                            </UtilityFragment>\n                          </li>\n                          <li>\n                            <UtilityFragment\n                              vFlex\n                              vFlexRow\n                              vAlignItems=\"start\"\n                              vGap={6}\n                              vPaddingHorizontal={8}\n                              vPaddingVertical={11}\n                            >\n                              <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                                <VisaIdeaTiny /> Make a suggestion\n                              </Button>\n                            </UtilityFragment>\n                          </li>\n                          <li>\n                            <UtilityFragment\n                              vFlex\n                              vFlexRow\n                              vAlignItems=\"start\"\n                              vGap={6}\n                              vPaddingHorizontal={8}\n                              vPaddingVertical={11}\n                            >\n                              <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" destructive>\n                                <VisaDeleteTiny /> Delete chat\n                              </Button>\n                            </UtilityFragment>\n                          </li>\n                        </Listbox>\n                      </UtilityFragment>\n                    </DropdownMenu>\n                  )}\n                </Utility>\n\n                {/* Scrollable chat history */}\n                <PanelBody\n                  style={{\n                    paddingTop: '10px',\n                    flex: 1,\n                    overflowY: 'auto',\n                    minHeight: 300,\n                  }}\n                >\n                  <Utility\n                    vFlex\n                    vFlexCol\n                    style={{\n                      flex: '1',\n                      overflow: 'auto',\n                    }}\n                  >\n                    {responses.map((response, index) => {\n                      // Show timestamp only on first message or when role changes\n                      const prev = responses[index - 1];\n                      const hideTimestamp = index !== 0 && response.role === prev?.role;\n\n                      return response.role === 'User 1' ? (\n                        <UserChatBubble\n                          key={`${id}-user-${index}`}\n                          id={`${id}-user-${index}`}\n                          response={response}\n                          hideAvatar={true}\n                          hideTimestamp={hideTimestamp}\n                        />\n                      ) : (\n                        <div style={{ marginInlineEnd: 48 }}>\n                          <ResponseChatBubble\n                            key={`${id}-response-${index}`}\n                            id={`${id}-response-${index}`}\n                            response={response}\n                            smallAvatar={true}\n                            hideTimestamp={hideTimestamp}\n                          />\n                        </div>\n                      );\n                    })}\n                  </Utility>\n                </PanelBody>\n                {/* Chat input at bottom of panel */}\n                <Utility\n                  vFlex\n                  vFlexCol\n                  vGap={8}\n                  vPadding={16}\n                  style={{\n                    flexShrink: 0,\n                  }}\n                >\n                  <ChatInput id={`${id}-input`} showCharacterCount={false} />\n                </Utility>\n              </PanelContent>\n            </Panel>\n          )}\n      </Utility>\n    </div>\n  );\n};\n\nexport default DefaultPanelChat;\n"
          },
          "name": "Default panel chat"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/user-chat-bubble.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/user-chat-bubble.tsx": "import { Typography, Utility } from '@visa/nova-react';\nimport Avatar from '@visa/nova-react/avatar';\nimport ChatActions from './chat-actions';\n\n/**\n * Props for the UserChatBubble component\n *\n * @property id - (optional) Base ID for element identification\n * @property hideAvatar - (optional) Completely hide avatar\n * @property smallAvatar - (optional) Use smaller avatar variant\n * @property response - Message object containing timestamp, message text, optional code, and sender role\n * @property hideTimestamp - (optional) Hide role and timestamp above bubble\n */\ntype Props = {\n  id?: string;\n  hideAvatar?: boolean;\n  smallAvatar?: boolean;\n  response: {\n    timeStamp: string;\n    message: string;\n    code?: string;\n    role: string;\n  };\n  hideTimestamp?: boolean;\n};\n\n/**\n * Message bubble for user-sent messages with right-aligned layout and avatar showing user's initials.\n * Includes optional timestamp header and actions menu, mirroring ResponseChatBubble layout but flipped for the user side.\n * Supports options to resize or hide/show the avatar, and hide/show timestamp.\n */\nconst UserChatBubble = ({ response, smallAvatar, hideAvatar, hideTimestamp, id = 'user-chat-bubble' }: Props) => {\n  return (\n    <>\n      <Utility\n        vFlex\n        vAlignItems=\"start\"\n        vFlexRowReverse\n        vAlignSelf=\"stretch\"\n        vGap={8}\n        vPaddingBottom={hideTimestamp ? 20 : 4}\n      >\n        {!hideAvatar && (\n          <div style={{ paddingBlockStart: '18px' }}>\n            <Avatar small={smallAvatar} aria-label=\"Virtual assistant\">\n              {response.role.charAt(0).toUpperCase()}\n            </Avatar>\n          </div>\n        )}\n        <Utility\n          vFlex\n          vFlexCol\n          vAlignItems=\"end\"\n          vGap={4}\n          style={{\n            flex: '1 0 0',\n          }}\n        >\n          {!hideTimestamp && (\n            <Utility vFlex vGap={8}>\n              <Typography variant=\"label-small\"> {response.role}</Typography>\n              <Typography variant=\"label-small\"> {response.timeStamp}</Typography>\n            </Utility>\n          )}\n          {/* marginLeft prevents bubble from becoming too wide */}\n          <Utility vFlex vJustifyContent=\"center\" style={{ marginLeft: 88 }}>\n            <Utility\n              vFlex\n              vFlexCol\n              vGap={4}\n              id={id}\n              tabIndex={0}\n              aria-label={`${response.message} ${response.code} message from ${response.role} at ${response.timeStamp}. Press tab to navigate to more options.`}\n              style={{\n                paddingBlock: '12px',\n                paddingInline: '14px',\n                borderRadius: '10px',\n                backgroundColor: 'var(--palette-default-surface-3)',\n              }}\n            >\n              <Typography variant=\"body-2\">{response.message}</Typography>\n              <Utility vFlex vJustifyContent=\"end\" vGap={4}>\n                <ChatActions id={`${id}-actions`} />\n              </Utility>\n            </Utility>\n          </Utility>\n        </Utility>\n      </Utility>\n    </>\n  );\n};\n\nexport default UserChatBubble;\n"
          },
          "name": "User chat bubble"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/response-chat-bubble.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/response-chat-bubble.tsx": "import { VisaFlagTiny } from '@visa/nova-icons-react';\nimport Avatar from '@visa/nova-react/avatar';\nimport { Button, Typography, Utility } from '@visa/nova-react';\nimport ChatActions from './chat-actions';\nimport ChatCodeBlock from './chat-code-block';\n\n/**\n * Props for the ResponseChatBubble component\n *\n * @property id - (optional) Base ID for element identification\n * @property hideAvatar - (optional) Completely hide avatar\n * @property smallAvatar - (optional) Use smaller avatar variant\n * @property response - Message object containing timestamp, message text, optional code, and sender role\n * @property hideTimestamp - (optional) Hide role and timestamp above bubble\n */\ntype Props = {\n  id?: string;\n  hideAvatar?: boolean;\n  smallAvatar?: boolean;\n  response: {\n    timeStamp: string;\n    message: string;\n    code?: string;\n    role: string;\n  };\n  hideTimestamp?: boolean;\n};\nconst BASE_URL = import.meta.env.BASE_URL;\n\n/**\n * Message bubble for AI or assistant responses with left-aligned layout, AI avatar icon, and optional code block display.\n * Includes timestamp header, flag button, and actions dropdown for user feedback and interaction.\n * Supports options to resize or hide/show the avatar, and hide/show timestamp.\n */\nconst ResponseChatBubble = (({ response, smallAvatar, hideAvatar, hideTimestamp, id = 'response-chat-bubble' }: Props) => {\n  return (\n    <Utility style={{ maxInlineSize: 'calc(100cqi - 208px)' }}>\n      <Utility vFlex vAlignItems=\"start\" vAlignSelf=\"stretch\" vGap={8} vPaddingBottom={hideTimestamp ? 20 : 4}>\n\n        {/* AI avatar - only visible when timestamp shown */}\n        {!hideAvatar && <div style={{ paddingBlockStart: \"18px\", paddingInlineStart: hideTimestamp ? \"var(--size-responsive-32)\": \"0\" }}>\n          {!hideTimestamp &&\n            <Avatar small={smallAvatar} aria-label=\"Virtual assistant\">\n              <img src={`${BASE_URL}/chat-ai-avatar.svg`} alt=\"chat icon\" />\n            </Avatar>\n          }\n        </div>}\n        {/* Message content container */}\n\n        <Utility\n          vFlex\n          vFlexCol\n          vAlignItems=\"start\"\n          vGap={4}\n          style={{ paddingInlineStart: hideAvatar ? \"40px\" : \"0\" }}\n        >\n          {/* Role and timestamp header */}\n          {!hideTimestamp && <Utility vFlex vGap={8}>\n            <Typography variant=\"label-small\"> {response.role}</Typography>\n            <Typography variant=\"label-small\"> {response.timeStamp}</Typography>\n          </Utility>}\n          <Utility style={{ maxInlineSize: 'calc(100cqi - 208px)' }}>\n            <Utility vFlex vFlexCol vGap={6} vPaddingVertical={12} vPaddingHorizontal={14}\n              id={id}\n              tabIndex={0}\n              aria-label={`${response.message} ${response.code} message from ${response.role} at ${response.timeStamp}. Press tab to navigate to more options.`}\n              style={{\n                borderRadius: \"10px\",\n                backgroundColor: \"var(--palette-default-surface-highlight)\",\n                minInlineSize: \"fit-content\"\n\n              }}\n            >\n              <Typography variant=\"body-2\" style={{\n                wordWrap: \"break-word\",\n                wordBreak: \"break-word\",\n                whiteSpace: \"pre-wrap\",\n                overflowWrap: \"break-word\"\n              }}>\n                {response.message}\n              </Typography>\n              {/* Optional code block for displaying code snippets */}\n              {response.code && <ChatCodeBlock language=\"html\" code={response.code} />}\n              {/* Action buttons at bottom-right */}\n              <Utility vFlex vJustifyContent=\"end\" vGap={4}>\n                {/* Add onClick handler to enable flag action */}\n                <Button aria-label=\"action\" id={`${id}-flag-button`} buttonSize=\"small\" colorScheme=\"tertiary\" iconButton subtle>\n                  <VisaFlagTiny />\n                </Button>\n                <ChatActions id={`${id}-actions`} />\n              </Utility>\n            </Utility>\n          </Utility>\n        </Utility>\n      </Utility>\n    </Utility >\n  );\n});\n\nexport default ResponseChatBubble;\n"
          },
          "name": "Response chat bubble"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-actions.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-actions.tsx": "import { useClick, useFloating, useInteractions } from '@floating-ui/react';\nimport { VisaOptionHorizontalTiny } from '@visa/nova-icons-react';\nimport { useState } from 'react';\nimport { Button, DropdownButton, DropdownMenu, Listbox, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Props for the ChatActions component\n *\n * @property onClick - (optional) Click handler for button\n * @property id - (optional) ID for dropdown elements\n * @property tabIndex - (optional) tab index for keyboard navigation\n */\ntype Props = {\n  onClick?: () => void;\n  id?: string;\n  tabIndex?: number;\n};\n\n/**\n * Dropdown menu button for message-level actions used in both user and AI chat bubbles.\n * Uses Floating UI for dropdown positioning and supports keyboard navigation.\n */\nexport const ChatActions = ({ id, onClick, tabIndex }: Props) => {\n  const [open, setOpen] = useState(false);\n\n  // Floating UI for dropdown positioning\n  const { context, floatingStyles, refs } = useFloating({\n    open,\n    onOpenChange: setOpen,\n    placement: 'bottom-end',\n  });\n\n  const onFloatingClick = useClick(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([onFloatingClick]);\n\n  return (\n    <>\n      {/* More options menu button */}\n      <DropdownButton\n        buttonSize='small'\n        style={{\n          '--v-button-default-block-size': 'var(--size-scalable-26)',\n          '--v-button-default-border-radius': 'var(--size-rounded-small)',\n        } as React.CSSProperties}\n        onClick={onClick}\n        aria-controls={id}\n        aria-expanded={open}\n        aria-label=\"see more options\"\n        iconButton\n        colorScheme=\"tertiary\"\n        subtle\n        id={`${id}-button`}\n        ref={refs.setReference}\n        {...getReferenceProps({\n          onBlur: () => setOpen(false)\n        })}\n        tabIndex={tabIndex}\n      >\n        <VisaOptionHorizontalTiny />\n      </DropdownButton>\n      {/* Dropdown menu with action items - customize as needed */}\n      {open && (\n        <DropdownMenu\n          id={id}\n          aria-hidden={!open}\n          ref={refs.setFloating}\n          style={{ inlineSize: '180px', ...floatingStyles, zIndex: 9999 }}\n          {...getFloatingProps()}\n        >\n          <UtilityFragment vHide={!open}>\n            <Listbox>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 1\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 2\n                  </Button>\n                </UtilityFragment>\n              </li>\n              <li>\n                <UtilityFragment\n                  vFlex\n                  vFlexRow\n                  vAlignItems=\"start\"\n                  vGap={6}\n                  vPaddingHorizontal={8}\n                  vPaddingVertical={11}\n                >\n                  <Button className=\"v-listbox-item\" colorScheme=\"tertiary\" subtle>\n                    Label 2\n                  </Button>\n                </UtilityFragment>\n              </li>\n            </Listbox>\n          </UtilityFragment>\n        </DropdownMenu>\n      )}\n    </>\n  );\n};\nexport default ChatActions;\n"
          },
          "name": "Chat actions"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-code-block-css.module.scss"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-code-block-css.module.scss": ".codeSnippet {\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n  font-family: 'Menlo', 'Courier New', Courier, monospace;\n  font-size: 14px;\n  justify-content: center;\n  min-block-size: 50px;\n  min-inline-size: fit-content;\n  padding: 8px 3rem 8px 12px;\n}\n\n.overflowContainer {\n  border-radius: var(--size-rounded-large);\n  border: 1px solid var(--palette-default-border);\n  max-inline-size: calc(100cqi - 208px);\n  overflow: auto;\n  z-index: 0;\n}\n\n.codeContainer {\n  position: relative;\n}\n\n.copyButtonContainer {\n  background-color: var(--palette-default-surface-1);\n  border-radius: var(--v-button-default-border-radius-icon);\n  position: absolute;\n  z-index: 1;\n  inset-block-start: 6px;\n  inset-inline-end: 6px;\n}\n\n.copyButton {\n  --v-button-default-inline-size: 2.3rem;\n  --v-button-default-justify-content: start;\n  transition: all 0.2s ease;\n\n  span {\n    inline-size: 0;\n    overflow: hidden;\n    transition: all 0.2s ease;\n  }\n\n  &.copied {\n    --v-button-default-inline-size: 7rem;\n\n    &>span {\n      inline-size: 7rem;\n    }\n  }\n}\n\n.chatTextareaResize {\n  field-sizing: content;\n  block-size: auto;\n  min-height: 50px;\n  max-height: calc(4*var(--typography-body-2-line-height));\n}"
          },
          "name": "Chat code block CSS"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-code-block.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-code-block.tsx": "import { Button, Typography } from '@visa/nova-react';\nimport cn from 'clsx';\nimport { Highlight, themes } from 'prism-react-renderer';\nimport { useState } from 'react';\nimport Styles from './chat-code-block-css.module.scss';\nimport { VisaCheckmarkTiny, VisaCopyTiny } from '@visa/nova-icons-react';\n\n/**\n * Props for the ChatCodeBlock component\n *\n * @property className - (optional) Additional CSS class names\n * @property code - (optional) Code string to display\n * @property deprecated - (optional) Applies strikethrough styling\n * @property exampleName - (optional) Name used in aria-label\n * @property language - (optional) Programming language for syntax highlighting\n */\ntype CodeProperties = {\n  className?: string;\n  code?: string;\n  deprecated?: boolean;\n  exampleName?: string;\n  language?: string;\n};\n\n/**\n * Syntax-highlighted code block with copy-to-clipboard functionality and line numbers.\n * Uses prism-react-renderer with GitHub theme for highlighting and shows visual feedback when code is copied.\n */\nconst ChatCodeBlock = ({\n  className = '',\n  code = '',\n  deprecated,\n  exampleName = '',\n  language = 'typescript',\n  ...remainingProps\n}: CodeProperties) => {\n  const formattedCode = code.trim();\n  const [copied, setCopied] = useState(false);\n\n  // Copy code to clipboard with visual feedback\n  const copyToClipboard = (text: string) => {\n    if (!copied) {\n      navigator.clipboard.writeText(text);\n      setCopied(true);\n      // Reset after 2 seconds\n      window.setTimeout(() => setCopied(false), 2000);\n    }\n  };\n\n  return (\n    <Highlight code={formattedCode} language={language} theme={themes.github} {...remainingProps}>\n      {({ style, tokens, getLineProps, getTokenProps }) => (\n        <div className={Styles.codeContainer}>\n          {/* Copy button with success feedback */}\n          <div className={Styles.copyButtonContainer}>\n            <Button\n              aria-label={`Copy code snippet of ${exampleName}`}\n              buttonSize=\"small\"\n              className={cn(Styles.copyButton, copied && Styles.copied)}\n              colorScheme=\"tertiary\"\n              iconButton\n              onClick={() => copyToClipboard(formattedCode)}\n            >\n              {copied ? <VisaCheckmarkTiny /> : <VisaCopyTiny />}\n              <Typography tag=\"span\" variant=\"label-active\">\n                Copied!\n              </Typography>\n            </Button>\n          </div>\n          {/* Scrollable code container with line numbers */}\n          <div className={cn(Styles.overflowContainer)}>\n            <pre\n              className={cn(Styles.codeSnippet, className)}\n              style={{ ...style, textDecoration: deprecated ? 'line-through' : 'inherit' }}\n            >\n              {tokens.map((line, i) => (\n                <span {...getLineProps({ key: i, line })} key={i}>\n                  {/* Line number column */}\n                  <span\n                    style={{\n                      display: 'inline-block',\n                      opacity: '0.3',\n                      userSelect: 'none',\n                      width: '2em',\n                    }}\n                  >\n                    {i + 1}\n                  </span>\n                  {line.map((token, key) => (\n                    <span {...getTokenProps({ key, token })} key={key} />\n                  ))}\n                </span>\n              ))}\n            </pre>\n          </div>\n        </div>\n      )}\n    </Highlight>\n  );\n};\n\nexport default ChatCodeBlock;\n"
          },
          "name": "Chat code block"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-context.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-context.tsx": "import { createContext, type Dispatch, type SetStateAction } from 'react';\n\n/**\n * Message structure for conversation history\n *\n * @property timeStamp - Timestamp when the message was sent\n * @property message - The text content of the message\n * @property code - (optional) Code block for displaying code snippets. Ensure code format matches your syntax highlighter requirements\n * @property role - Identifies sender (e.g., \"User 1\", \"User 2\", \"AI Assistant\")\n */\ntype ResponseType = {\n  timeStamp: string;\n  message: string;\n  code?: string;\n  role: string;\n};\n\n/**\n * Context type for managing chat conversation state\n *\n * @property responses - Array of all messages in conversation\n * @property setResponses - Setter to update conversation\n */\ntype ChatContextType = {\n  responses: ResponseType[];\n  setResponses: Dispatch<SetStateAction<ResponseType[]>>;\n};\n\n// Default empty context value\nconst defaultContextValue: ChatContextType = {\n  responses: [],\n  setResponses: () => {},\n};\n\n/**\n * React Context object that stores shared conversation state for the chat application.\n * Context is a React pattern for sharing data between components without passing it through intermediate components.\n * Components access this via React's useContext hook when rendered inside ChatProvider.\n */\nconst ChatContext = createContext<ChatContextType>(defaultContextValue);\n\nexport default ChatContext;\n"
          },
          "name": "Chat context"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-input.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-input.tsx": "import { VisaAttachmentTiny, VisaErrorTiny, VisaMicrophoneTiny, VisaSendTiny } from '@visa/nova-icons-react';\nimport { Button, InputContainer, InputMessage, Label, Textarea, Utility } from '@visa/nova-react';\nimport { useContext, useState, useEffect, type ChangeEvent } from 'react';\nimport ChatContext from './chat-context';\nimport Styles from './chat-code-block-css.module.scss';\n\n// Maximum characters allowed per message\nconst maxCharacters = 100000;\n\n/**\n * Props for the ChatInput component\n *\n * @property id - (optional) ID for the input element\n * @property style - (optional) Custom CSS styles for the input container\n * @property showCharacterCount - (optional) Toggle character count display\n */\ntype Props = {\n  id?: string;\n  style?: React.CSSProperties;\n  showCharacterCount?: boolean;\n};\n\n/**\n * Multi-line textarea input with character counter, validation, and quick action buttons for chat messages.\n * Auto-expands as user types, validates on submission, and integrates with ChatContext to add messages to the conversation.\n */\nconst ChatInput = ({ style, id = 'chat-input', showCharacterCount = true }: Props) => {\n  /**\n   * Generates the helper message displayed below the input field.\n   * @param characterCount - Current number of characters typed\n   * @param characterCountInvalid - Whether user exceeded character limit\n   * @param invalid - Whether user tried to submit empty message\n   * @return Error message, character count, or over-limit warning\n   */\n  const getMessage = ({\n    characterCount,\n    characterCountInvalid,\n    invalid,\n  }: {\n    characterCount: number;\n    characterCountInvalid: boolean;\n    invalid: boolean;\n  }) => {\n    if (invalid) return \"Input field can't be empty. Please enter a message to continue.\";\n    if (showCharacterCount) {\n      if (characterCountInvalid)\n        return `${(characterCount - maxCharacters).toLocaleString()} character${\n          characterCount - maxCharacters !== 1 ? 's' : ''\n        } over limit`;\n      return `${(maxCharacters - characterCount).toLocaleString()} character${\n        maxCharacters - characterCount !== 1 ? 's' : ''\n      } remaining`;\n    }\n  };\n\n  // Access shared chat context - setResponses adds messages, responses holds all messages\n  const { setResponses, responses } = useContext(ChatContext);\n\n  // Track error state (true when user submits empty message)\n  const [invalid, setInvalid] = useState(false);\n\n  // Track current text in textarea\n  const [text, setText] = useState('');\n\n  // Clear error state when conversation is reset (all messages cleared)\n  useEffect(() => {\n    setInvalid(false);\n  }, [responses]);\n\n  const characterCount = text.length;\n  const characterCountInvalid = characterCount > maxCharacters;\n  const messageIsError = characterCountInvalid || invalid;\n  const message = getMessage({ characterCount, characterCountInvalid, invalid });\n\n  /**\n   * Clears the input field and error state.\n   * @param e - Form reset event\n   */\n  const onReset = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    setInvalid(false);\n    setText('');\n  };\n\n  /**\n   * Validates input and adds message to conversation if valid.\n   * @param e - Form submit event\n   */\n  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    setInvalid(characterCount === 0);\n    if (characterCount === 0) return;\n\n    // Add new message to conversation with timestamp and role\n    setResponses(prevResponses => [\n      ...prevResponses,\n      {\n        timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n        message: text,\n        role: 'User 1', // Update this to match your user identification\n      },\n    ]);\n    setText('');\n  };\n\n  /**\n   * Updates text state as user types and clears error state.\n   * @param e - Input change event\n   */\n  const onTextChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n    setInvalid(false);\n    setText(e.target.value);\n  };\n\n  return (\n    <form onReset={onReset} onSubmit={onSubmit}>\n      <Utility vFlex vFlexCol vGap={4}>\n        {/* Empty label maintains consistent spacing in design system */}\n        <Label />\n        <InputContainer\n          className=\"v-flex-row\"\n          style={{\n            ...style,\n            position: 'relative',\n          }}\n        >\n          <Textarea\n            aria-describedby={`${id}-message`}\n            aria-invalid={characterCountInvalid || invalid}\n            aria-required=\"true\"\n            aria-label=\"Chat input\"\n            id={id}\n            fixed\n            name={'test'}\n            onChange={onTextChange}\n            onKeyDown={e => {\n              if (e.key === 'Enter') {\n                e.preventDefault();\n                setInvalid(characterCount === 0);\n                if (characterCount === 0) return;\n                setResponses(prevResponses => [\n                  ...prevResponses,\n                  {\n                    timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n                    message: text,\n                    role: 'User 1', // Update this to match your user identification\n                  },\n                ]);\n                setText('');\n              }\n            }}\n            value={text}\n            placeholder=\"Start typing...\"\n            style={{\n              marginTop: '0px',\n              marginBlockEnd: '40px',\n            }}\n            className={Styles.chatTextareaResize}\n          />\n          <div\n            style={{\n              position: 'absolute',\n              right: '8px',\n              bottom: '6px',\n              display: 'flex',\n              gap: '6px',\n              alignItems: 'center',\n              zIndex: 1000,\n            }}\n          >\n            {/* Actions for voice recording and file attachment. Add actions relevant to your use case. */}\n            <Button aria-label=\"record\" type=\"button\" colorScheme=\"tertiary\" iconButton subtle>\n              <VisaMicrophoneTiny />\n            </Button>\n            <Button aria-label=\"files\" type=\"button\" colorScheme=\"tertiary\" iconButton subtle>\n              <VisaAttachmentTiny />\n            </Button>\n            <Button\n              aria-label=\"send\"\n              type=\"submit\"\n              iconButton\n              subtle\n              colorScheme=\"tertiary\"\n              style={{ blockSize: '32px', inlineSize: '32px', padding: '7px' }}\n            >\n              <VisaSendTiny />\n            </Button>\n          </div>\n        </InputContainer>\n        <InputMessage\n          aria-atomic={messageIsError}\n          aria-live={messageIsError ? 'assertive' : 'polite'}\n          id={`${id}-message`}\n          role={messageIsError ? 'alert' : undefined}\n        >\n          {messageIsError && <VisaErrorTiny />}\n          {message}\n        </InputMessage>\n      </Utility>\n    </form>\n  );\n};\n\nexport default ChatInput;\n"
          },
          "name": "Chat input"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-provider.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-provider.tsx": "import { useState, type ReactNode } from 'react';\nimport ChatContext from './chat-context';\n\n/**\n * Message structure for conversation history\n *\n * @property timeStamp - Timestamp when the message was sent\n * @property message - The text content of the message\n * @property code - (optional) Code block for displaying code snippets. Ensure code format matches your syntax highlighter requirements\n * @property role - Identifies sender (e.g., \"User 1\", \"User 2\", \"AI Assistant\")\n */\ntype ResponseType = {\n  timeStamp: string;\n  message: string;\n  code?: string;\n  role: string;\n};\n\n/**\n * React Context provider for sharing chat conversation state across multiple components.\n * Wraps children with ChatContext to provide responses array and setter as a single source of truth for message history.\n *\n * @param children - React components to wrap with chat context\n */\nconst ChatProvider = ({ children }: { children: ReactNode }) => {\n  const [responses, setResponses] = useState<ResponseType[]>([]);\n\n  return <ChatContext.Provider value={{ responses, setResponses }}>{children}</ChatContext.Provider>;\n};\n\nexport default ChatProvider;\n"
          },
          "name": "Chat provider"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/chat-suggestions.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/chat-suggestions.tsx": "import { Checkbox, Chip, Typography, Utility } from '@visa/nova-react';\nimport { useContext } from 'react';\nimport ChatContext from './chat-context';\n\nconst id = 'chat-suggestion';\n\n// Replace with prompts relevant to your use case\nconst chips = ['How do I reset my password?', 'Summarize a document', 'Find a report'];\n\n/**\n * Prompt suggestion chips displayed when conversation is empty that users can click to auto-populate input.\n * Clicking a chip adds it as a user message to ChatContext and starts the conversation.\n */\nconst ChatSuggestions = () => {\n  const { setResponses } = useContext(ChatContext);\n\n  return (\n    <Utility vFlex vFlexCol vAlignItems=\"end\" vGap={8}>\n      <Typography variant=\"label-large\">Prompt suggestions</Typography>\n      <Utility vFlex vFlexWrap vGap={8} vAlignItems=\"end\" vJustifyContent=\"end\">\n        {chips.map((chip, index) => (\n          <Chip<'label'>\n            chipType=\"selection\"\n            htmlFor={`${id}-${index}`}\n            key={`${id}-${index}`}\n            tag=\"label\"\n            style={{ maxBlockSize: '32px', minBlockSize: 'fit-content' }}\n          >\n            <span style={{ textWrap: 'pretty' }}>{chip}</span>\n            <Checkbox\n              aria-label={chip}\n              id={`${id}-${index}`}\n              onChange={() => {\n                setResponses([\n                  {\n                    timeStamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),\n                    message: chip,\n                    role: 'User 1',\n                  },\n                ]);\n              }}\n            />\n          </Chip>\n        ))}\n      </Utility>\n    </Utility>\n  );\n};\n\nexport default ChatSuggestions;\n"
          },
          "name": "Chat suggestions"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/chat/responses.json"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/chat/shared/responses.json": "{\n    \"exampleResponses\": [\n        {\n            \"message\": \"This is a sent message.\",\n            \"role\": \"User 1\",\n            \"timeStamp\": \"12:08pm\"\n        },\n        {\n            \"message\": \"This is a received message.\",\n            \"role\": \"User 2\",\n            \"timeStamp\": \"12:08pm\"\n        },\n        {\n            \"message\": \"This is a sent message.\",\n            \"role\": \"User 1\",\n            \"timeStamp\": \"12:08pm\"\n        },\n        {\n            \"message\": \"This is a received message. ~~~js const aJsVariable = 'test' console.log(aJsVariable);~~~\",\n            \"role\": \"User 2\",\n            \"timeStamp\": \"12:08pm\"\n        },\n        {\n            \"message\": \"This is a sent message.\",\n            \"role\": \"User 1\",\n            \"timeStamp\": \"12:08pm\"\n        },\n        {\n            \"message\": \"This is a received message.\",\n            \"role\": \"User 2\",\n            \"timeStamp\": \"12:08pm\"\n        }\n    ]\n}"
          },
          "name": "Responses"
        }
      ],
      "propertySections": [],
      "properties": []
    },
    {
      "name": "dynamic-table",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "patterns",
      "exampleSections": [
        {
          "name": "Default dynamic tables",
          "description": "",
          "order": 1
        },
        {
          "name": "Dynamic table loading states",
          "description": "",
          "order": 2
        },
        {
          "name": "Multi-select dynamic tables",
          "description": "",
          "order": 3
        },
        {
          "name": "Expandable dynamic tables",
          "description": "",
          "order": 4
        },
        {
          "name": "Dynamic table layouts",
          "description": "",
          "order": 5
        },
        {
          "name": "Dynamic table with filters",
          "description": "",
          "order": 6
        },
        {
          "name": "Shared Components",
          "description": "",
          "order": 7
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/default",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/default.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/default.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr, Utility } from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { getDefaultColumnData, generateBasicData } from './shared/generate-demo-data.utils';\n\n/**\n * Basic sortable data table.\n */\nconst DefaultDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(4, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Default dynamic table.</ScreenReader>\n        <Thead>\n          <Tr>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default DefaultDynamicTable;\n"
          },
          "name": "Default table"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/multiple-action-buttons",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/multiple-action-buttons.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/multiple-action-buttons.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { VisaDeleteTiny, VisaEditTiny } from '@visa/nova-icons-react';\nimport { TableWrapper, Table, ScreenReader, Thead, Tr, Th, Tbody, Td, Button, Utility } from '@visa/nova-react';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport {\n  type ColData,\n  SortType,\n  type RowDataMultiActions,\n  ActionButtons,\n  type RowData,\n  type SortKeyType,\n} from './shared/dynamic-table.constants';\nimport './shared/dynamic-table.scss';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Table with multiple action buttons per row, allowing users to perform different operations\n * (edit, delete, etc.) directly from each row.\n */\nconst MultipleActionButtonsDynamicTable = () => {\n  // Generate demo data with default columns\n  const defaultColumnData: ColData[] = getDefaultColumnData(false);\n  const defaultRowData: RowData[] = generateBasicData(4, defaultColumnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = defaultColumnData.find(col => col.identifier)?.name || defaultColumnData[0].name;\n\n  // Extend column data to include actions column\n  const columnData: ColData[] = [\n    ...defaultColumnData,\n    {\n      name: 'Actions',\n      compact: true,\n      sortable: false,\n      renderActionButtons: (row: RowDataMultiActions) => (\n        <div className=\"actions-wrapper\">\n          {Array.isArray(row.Actions) &&\n            row.Actions.map((action, actionIndex) => (\n              <Button\n                key={`${action}-${actionIndex}`}\n                aria-label={`${action} ${row[identifyingColumn]}`}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n              >\n                {/* with more options, you could store in the same object as ActionButtons */}\n                {action === ActionButtons.EDIT ? <VisaEditTiny /> : <VisaDeleteTiny />}\n              </Button>\n            ))}\n        </div>\n      ),\n    },\n  ];\n\n  // add an 'Actions' property to indicate multiple actions\n  const data: RowDataMultiActions[] = defaultRowData.map(row => ({\n    ...row,\n    Actions: [ActionButtons.EDIT, ActionButtons.DELETE],\n  }));\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    // Remove action buttons before sorting to use shared sorting logic\n    const sortedDataNoActions: RowData[] = data.map(row => {\n      const { ...rest } = row;\n      // Set Actions to true\n      return { ...rest, Actions: '' };\n    });\n    const sortedRowData = revisedSortTableData(sortKey, columnData, sortedDataNoActions);\n    // Restore action buttons after sorting to maintain original data structure\n    const restoredSortedData: RowDataMultiActions[] = sortedRowData.map(row => {\n      // because the data is sorted, we need to find the original row to get its Actions\n      const originalRow = data.find(d => d.id === row.id);\n      return {\n        ...row,\n        Actions: originalRow ? originalRow.Actions : [],\n      };\n    });\n    return restoredSortedData;\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with multiple action buttons.</ScreenReader>\n        <Thead>\n          <Tr>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                className={col.compact ? 'compact-column' : ''}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.renderActionButtons\n                    ? col.renderActionButtons(row)\n                    : col.render\n                      ? col.render(row as RowData)\n                      : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default MultipleActionButtonsDynamicTable;\n"
          },
          "name": "Table with multiple action buttons"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/column-header-actions",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/column-header-actions.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/column-header-actions.tsx": "import { Button, ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr, Utility } from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport { useMemo, useState, type CSSProperties } from 'react';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\nimport { VisaEditTiny } from '@visa/nova-icons-react';\n\n/**\n * Sortable data table with expandable action menus in column headers.\n */\nconst ColumnHeaderActionsComponent = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData(true).map(col => {\n    col.genericHeaderActions = true;\n    if (col.name === 'Actions') {\n      col.render = (row: RowData) => (\n        <Button aria-label={`Edit ${row[identifyingColumn]}`} buttonSize=\"small\" colorScheme=\"tertiary\" iconButton>\n          <VisaEditTiny />\n        </Button>\n      );\n    }\n    return col;\n  });\n  const data: RowData[] = generateBasicData(4, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for open/closed column headers\n  const [colHeadersOpen, setColHeadersOpen] = useState<boolean[]>(columnData.map(() => false));\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with column header actions.</ScreenReader>\n        <Thead>\n          <Tr>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    open={colHeadersOpen[index]}\n                    setOpen={(isOpen: boolean) => {\n                      const updatedOpenStates = [...colHeadersOpen];\n                      updatedOpenStates[index] = isOpen;\n                      setColHeadersOpen(updatedOpenStates);\n                    }}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default ColumnHeaderActionsComponent;\n"
          },
          "name": "Table with column header actions"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/vertical-scroll-and-sticky-row",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/vertical-scroll-and-sticky-row.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/vertical-scroll-and-sticky-row.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { TableWrapper, Table, ScreenReader, Thead, Tr, Th, Utility, Tbody, Td } from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Fixed-height table with vertical scrolling and sticky header row.\n */\nconst VerticalScrollAndStickyRowDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(10, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]); // holds filtered data\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper style={{ '--v-table-wrapper-block-size': '288px' } as CSSProperties}>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n        className=\"fixed-table\"\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with vertical scroll and sticky row.</ScreenReader>\n        <Thead>\n          <Tr className=\"sticky-row\">\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default VerticalScrollAndStickyRowDynamicTable;\n"
          },
          "name": "Table with vertical scroll and sticky row"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/pinned-column-and-horizontal-scroll",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/pinned-column-and-horizontal-scroll.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/pinned-column-and-horizontal-scroll.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr, Utility } from '@visa/nova-react';\nimport cn from 'clsx';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { toggleColumnDropdown } from './shared/filters.utils';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\nimport StatusBadge from './shared/badge';\n\n/**\n * Table with column pinning.\n */\nconst PinnedColumnAndHorizontalScrollDynamicTable = () => {\n  // Use state for columnData since it needs to be modified (pinned property)\n  const defaultColumnData: ColData[] = getDefaultColumnData().slice(-2); // get last two columns from default data\n  const columnData: ColData[] = [\n    { name: 'Column A', sortable: true, genericHeaderActions: true },\n    { name: 'Column B', sortable: true, genericHeaderActions: true },\n    { name: 'Column C', sortable: true, genericHeaderActions: true },\n    { name: 'Column D', sortable: true, genericHeaderActions: true },\n    { name: 'Column E', sortable: true, genericHeaderActions: true },\n    { name: 'Column F', sortable: true, genericHeaderActions: true },\n    { name: 'Column G', sortable: true, genericHeaderActions: true },\n    { name: 'Column H', sortable: true, genericHeaderActions: true },\n    { name: 'Column I', sortable: true, genericHeaderActions: true },\n    { name: 'Column J', sortable: true, genericHeaderActions: true },\n    { name: 'Column K', sortable: true, genericHeaderActions: true },\n    ...defaultColumnData.map(col =>\n      // rename badge column to 'Column L' to avoid duplicate names\n      col.badge ? { ...col, name: 'Column L', render: (row: RowData) => <StatusBadge label={row['Column L']} /> } : col\n    ),\n  ];\n  // Generate demo data\n  const data: RowData[] = generateBasicData(8, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for pinned column, default to Column D\n  const [pinnedColumn, setPinnedColumn] = useState<ColData | null>(columnData[3]); // Column D\n\n  // Determine visible columns based on pinned and hidden properties\n  const visibleColumns = useMemo(() => {\n    if (pinnedColumn) {\n      return [pinnedColumn, ...columnData.filter(col => col.name !== pinnedColumn.name)];\n    }\n    return columnData;\n  }, [columnData]);\n\n  // State for column dropdowns\n  const [columnFiltersOpen, setColumnFiltersOpen] = useState<boolean[]>(columnData.map(() => false));\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n        className=\"fixed-table\"\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with pinned column and horizontal scroll.</ScreenReader>\n        <Thead>\n          <Tr>\n            {visibleColumns.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    pinned={col.name === pinnedColumn?.name}\n                    onPin={() => {\n                      setPinnedColumn(prev => {\n                        if (prev && prev === col) {\n                          // unpin the column\n                          return null;\n                        } else {\n                          // pin the new column\n                          return col;\n                        }\n                      });\n                      const index = columnData.indexOf(col);\n                      toggleColumnDropdown(index, columnFiltersOpen, setColumnFiltersOpen);\n                    }}\n                    open={columnFiltersOpen[columnData.indexOf(col)]}\n                    setOpen={(isOpen: boolean) => {\n                      const index = columnData.indexOf(col);\n                      toggleColumnDropdown(index, columnFiltersOpen, setColumnFiltersOpen, isOpen);\n                    }}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {visibleColumns.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default PinnedColumnAndHorizontalScrollDynamicTable;\n"
          },
          "name": "Table with pinned column and horizontal scroll"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/vertical-and-horizontal-scroll",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/vertical-and-horizontal-scroll.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/vertical-and-horizontal-scroll.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr, Utility } from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { toggleColumnDropdown } from './shared/filters.utils';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\nimport StatusBadge from './shared/badge';\n\n/**\n * Fixed-height table with both vertical and horizontal scrolling.\n */\nconst VerticalAndHorizontalScrollDynamicTable = () => {\n  // Generate demo data\n  const defaultColumnData: ColData[] = getDefaultColumnData().slice(-2); // get last two columns from default data\n  const columnData: ColData[] = [\n    { name: 'Column A', sortable: true, genericHeaderActions: true },\n    { name: 'Column B', sortable: true, genericHeaderActions: true },\n    { name: 'Column C', sortable: true, genericHeaderActions: true },\n    { name: 'Column D', sortable: true, genericHeaderActions: true },\n    { name: 'Column E', sortable: true, genericHeaderActions: true },\n    { name: 'Column F', sortable: true, genericHeaderActions: true },\n    { name: 'Column G', sortable: true, genericHeaderActions: true },\n    { name: 'Column H', sortable: true, genericHeaderActions: true },\n    { name: 'Column I', sortable: true, genericHeaderActions: true },\n    { name: 'Column J', sortable: true, genericHeaderActions: true },\n    { name: 'Column K', sortable: true, genericHeaderActions: true },\n    ...defaultColumnData.map(col =>\n      // rename badge column to 'Column L' to avoid duplicate names\n      col.badge ? { ...col, name: 'Column L', render: (row: RowData) => <StatusBadge label={row['Column L']} /> } : col\n    ),\n  ];\n  const data: RowData[] = generateBasicData(12, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for column dropdowns\n  const [columnFiltersOpen, setColumnFiltersOpen] = useState<boolean[]>(columnData.map(() => false));\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]); // holds filtered data\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper style={{ '--v-table-wrapper-block-size': '288px' } as CSSProperties}>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with vertical and horizontal scroll.</ScreenReader>\n        <Thead>\n          <Tr>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    open={columnFiltersOpen[columnData.indexOf(col)]}\n                    setOpen={(isOpen: boolean) => {\n                      const index = columnData.indexOf(col);\n                      toggleColumnDropdown(index, columnFiltersOpen, setColumnFiltersOpen, isOpen);\n                    }}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default VerticalAndHorizontalScrollDynamicTable;\n"
          },
          "name": "Table with vertical and horizontal scroll"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Default dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/notifications",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/notifications.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/notifications.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport {\n  Badge,\n  BadgeEllipse,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Utility,\n} from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n// Extend ColData to include optional notification property\ninterface ExtendedColData extends ColData {\n  notification?: boolean;\n}\n\n/**\n * Table with a notification indicator column.\n */\nconst NotificationsDynamicTable = () => {\n  // Generate demo data with default columns\n  const defaultColumnData: ExtendedColData[] = getDefaultColumnData();\n  const defaultRowData: RowData[] = generateBasicData(4, defaultColumnData);\n\n  /** Extend data to include notifications */\n  const columnData: ExtendedColData[] = [\n    {\n      name: 'New',\n      notification: true,\n      sortable: true,\n      compact: true,\n      render: (row: RowData) =>\n        row['New'] !== '' && (\n          <Badge badgeType=\"neutral\" clear>\n            <BadgeEllipse />\n            <span className=\"v-sr\">New notification</span>\n          </Badge>\n        ),\n    },\n    ...defaultColumnData,\n  ];\n\n  // add a 'New' property to indicate new notifications\n  // Assign notifications to every other row initially, but they persist with rows when sorted\n  const data: RowData[] = defaultRowData.map((row, index) => ({\n    New: index % 2 === 0 ? 'email' : '',\n    ...row,\n  }));\n\n  // State for sorting, default to descending on 'New' notification column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: 'New', direction: SortType.DESC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]); // holds filtered data\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with notifications.</ScreenReader>\n        <Thead>\n          <Tr>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact && !col.notification ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default NotificationsDynamicTable;\n"
          },
          "name": "Table with notifications"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table loading states",
          "url": {
            "iframe": "patterns/dynamic-table/indeterminate-linear-progress",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/indeterminate-linear-progress.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/indeterminate-linear-progress.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport {\n  Button,\n  ProgressLabel,\n  ProgressLinear,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Sortable data table with linear progress indicator during data fetching.\n */\nconst IndeterminateLinearProgressDynamicTable = () => {\n  // State for loading and reset\n  const [loading, setLoading] = useState(false);\n  const [reset, setReset] = useState(false);\n\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const [data, setData] = useState<RowData[]>([]);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Simulates data loading upon button click.\n   */\n  const loadTableData = () => {\n    setLoading(true);\n    setReset(false);\n    setTimeout(() => {\n      setLoading(false);\n      setData(generateBasicData(4, columnData));\n    }, 3000); // simulate data loading delay for 3 seconds\n  };\n\n  /**\n   * Resets table data to empty state.\n   */\n  const resetData = () => {\n    setLoading(false);\n    setData([]);\n    setReset(true);\n  };\n\n  return (\n    <Utility vFlexCol vGap=\"8\">\n      <Utility vFlex vGap=\"16\" vAlignItems=\"start\">\n        <Button aria-pressed={loading || sortedData.length > 0} onClick={loadTableData}>\n          Load data\n        </Button>\n        <Button colorScheme=\"secondary\" aria-pressed={reset} onClick={resetData}>\n          Reset\n        </Button>\n      </Utility>\n      <TableWrapper>\n        <Table\n          style={\n            {\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n          aria-busy={loading}\n        >\n          <ScreenReader tag=\"caption\">Default dynamic table with indeterminate linear progress.</ScreenReader>\n          <Thead>\n            <Tr>\n              {columnData.map((col, index) => (\n                <Th\n                  key={index}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    <ActionsButton\n                      column={col}\n                      label={col.name}\n                      onSort={direction => sort(col, direction)}\n                      sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    />\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {loading ? (\n              <Tr>\n                <Td colSpan={columnData.length} style={{ textAlign: 'center' }}>\n                  <Utility vFlex vJustifyContent=\"center\" vPaddingVertical={8}>\n                    <UtilityFragment vMarginVertical={8}>\n                      <ProgressLinear id=\"linear-progress-loading\" />\n                    </UtilityFragment>\n                    <ProgressLabel htmlFor=\"linear-progress-loading\" className=\"v-sr\">\n                      <Utility tag=\"span\" role=\"alert\">\n                        Loading\n                      </Utility>\n                    </ProgressLabel>\n                  </Utility>\n                </Td>\n              </Tr>\n            ) : sortedData.length > 0 ? (\n              sortedData.map((row, rowIndex) => (\n                <Tr key={rowIndex}>\n                  {columnData.map((col, colIndex) => (\n                    <Td\n                      key={colIndex}\n                      scope={col.identifier ? 'row' : undefined}\n                      className={col.compact ? 'compact-column' : ''}\n                      data-label={col.name}\n                    >\n                      {col.render ? col.render(row) : row[col.name]}\n                    </Td>\n                  ))}\n                </Tr>\n              ))\n            ) : null}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n    </Utility>\n  );\n};\n\nexport default IndeterminateLinearProgressDynamicTable;\n"
          },
          "name": "Table with indeterminate linear progress"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table loading states",
          "url": {
            "iframe": "patterns/dynamic-table/indeterminate-circular-progress",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/indeterminate-circular-progress.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/indeterminate-circular-progress.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport {\n  Button,\n  ProgressCircular,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Sortable data table with circular progress indicator during data fetching.\n */\nconst IndeterminateCircularProgressDynamicTable = () => {\n  // State for loading and reset\n  const [loading, setLoading] = useState(false);\n  const [reset, setReset] = useState(false);\n\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const [data, setData] = useState<RowData[]>([]);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Simulates data loading upon button click.\n   */\n  const loadTableData = () => {\n    setLoading(true);\n    setReset(false);\n    setTimeout(() => {\n      setLoading(false);\n      setData(generateBasicData(4, columnData));\n    }, 3000); // simulate data loading delay for 3 seconds\n  };\n\n  /**\n   * Resets table data to empty state.\n   */\n  const resetData = () => {\n    setLoading(false);\n    setData([]);\n    setReset(true);\n  };\n\n  return (\n    <Utility vFlexCol vGap=\"8\">\n      <Utility vFlex vGap=\"16\" vAlignItems=\"start\">\n        <Button aria-pressed={loading || sortedData.length > 0} onClick={loadTableData}>\n          Load data\n        </Button>\n        <Button colorScheme=\"secondary\" aria-pressed={reset} onClick={resetData}>\n          Reset\n        </Button>\n      </Utility>\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // Use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n          aria-busy={loading}\n        >\n          <ScreenReader tag=\"caption\">Default dynamic table with indeterminate circular progress.</ScreenReader>\n          <Thead>\n            <Tr>\n              {columnData.map((col, index) => (\n                <Th\n                  key={index}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    <ActionsButton\n                      column={col}\n                      label={col.name}\n                      onSort={direction => sort(col, direction)}\n                      sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    />\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {loading ? (\n              <Tr>\n                {/* vertical padding gives space for progress indicator without a scrollbar popping up */}\n                <Td colSpan={columnData.length} style={{ textAlign: 'center', paddingBlock: '20px' }}>\n                  <UtilityFragment vFlex vJustifyContent=\"center\">\n                    <ProgressCircular indeterminate>\n                      <span className=\"v-sr\" role=\"alert\">\n                        Loading\n                      </span>\n                    </ProgressCircular>\n                  </UtilityFragment>\n                </Td>\n              </Tr>\n            ) : sortedData.length > 0 ? (\n              sortedData.map((row, rowIndex) => (\n                <Tr key={rowIndex}>\n                  {columnData.map((col, colIndex) => (\n                    <Td\n                      key={colIndex}\n                      scope={col.identifier ? 'row' : undefined}\n                      className={col.compact ? 'compact-column' : ''}\n                      data-label={col.name}\n                    >\n                      {col.render ? col.render(row) : row[col.name]}\n                    </Td>\n                  ))}\n                </Tr>\n              ))\n            ) : null}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n    </Utility>\n  );\n};\n\nexport default IndeterminateCircularProgressDynamicTable;\n"
          },
          "name": "Table with indeterminate circular progress"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table loading states",
          "url": {
            "iframe": "patterns/dynamic-table/data-fetch-on-accordion-toggle",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/data-fetch-on-accordion-toggle.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/data-fetch-on-accordion-toggle.tsx": "import { useEffect, useMemo, useState, type CSSProperties } from 'react';\nimport {\n  AccordionToggleIcon,\n  Button,\n  ProgressLinear,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { columnDataFilterDefaults } from './shared/generate-demo-data.utils';\nimport { getTablePage, getAccordionData } from './shared/mock-table-api.utils';\n\n/**\n * Represents the state of accordion row data for lazy loading.\n *\n * @property data - The fetched row data, null if not yet loaded or loading\n * @property loading - Whether the data is currently being fetched\n */\ninterface AccordionRowData {\n  data: RowData | null;\n  loading: boolean;\n}\n\n/**\n * Accordion table with lazy loading of row details on expansion.\n */\nconst DataFetchOnAccordionToggleDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = [...columnDataFilterDefaults];\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n  const [data, setData] = useState<RowData[]>([]);\n\n  // State for expanded rows\n  const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({});\n  // State for header toggle\n  const [headerToggle, setHeaderToggle] = useState(false);\n  // state for accordion panel data\n  const [accordionData, setAccordionData] = useState<Record<string, AccordionRowData>>({});\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Fetches initial table data from mock API.\n   */\n  useEffect(() => {\n    const getData = async () => {\n      // Fetch just the first 4 rows for this example\n      const response = await getTablePage(1, 4, sortKey, columnData, 0);\n      setData(response.data);\n    };\n    getData();\n  }, []);\n\n  /**\n   * Loads accordion panel data for a specific row using the mock API service.\n   *\n   * @param rowId - The identifier of the row to load data for\n   */\n  const loadAccordionData = (rowId: string) => {\n    // Set loading state using functional update to avoid race conditions\n    setAccordionData(prevData => ({\n      ...prevData,\n      [rowId]: { data: null, loading: true },\n    }));\n\n    // Call the mock API service to fetch accordion data\n    getAccordionData(rowId).then(rowData => {\n      // Update state with fetched data\n      setAccordionData(prevData => ({\n        ...prevData,\n        [rowId]: { data: rowData, loading: false },\n      }));\n    });\n  };\n\n  /**\n   * Toggles individual row expansion state.\n   *\n   * @param name - Row name to toggle\n   */\n  const toggleRow = (name: string) => {\n    if (expandedRows[name]) {\n      const updatedExpandedRows = { ...expandedRows };\n      delete updatedExpandedRows[name];\n      setExpandedRows(updatedExpandedRows);\n    } else {\n      setExpandedRows({ ...expandedRows, [name]: true });\n      // If accordion data for this row is not already fetched, fetch it\n      if (!accordionData[name]) {\n        // Set loading state\n        loadAccordionData(name);\n      }\n    }\n\n    // Check if all rows are expanded after the toggle and update header toggle state\n    const allExpanded = Object.keys(expandedRows).length === sortedData.length;\n    setHeaderToggle(allExpanded);\n  };\n\n  /**\n   * Toggles all rows expansion state.\n   */\n  const toggleAllRows = () => {\n    const isExpanded = !headerToggle;\n    setHeaderToggle(isExpanded);\n\n    // Update all rows to match the header toggle state\n    if (isExpanded) {\n      const allExpandedRows: Record<string, boolean> = {};\n      sortedData.forEach(row => {\n        const rowId = row[identifyingColumn];\n        allExpandedRows[rowId] = true;\n\n        // If accordion data for this row is not already fetched, fetch it\n        if (!accordionData[rowId]) {\n          loadAccordionData(rowId);\n        }\n      });\n      setExpandedRows(allExpandedRows);\n    } else {\n      setExpandedRows({});\n    }\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        className=\"v-accordion accordion-style-table\"\n      >\n        <ScreenReader tag=\"caption\">Multi row expandable table.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Td className=\"v-th compact-column\">\n              <Button\n                aria-expanded={!!headerToggle}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                aria-label={headerToggle ? 'Collapse all rows' : 'Expand all rows'}\n                onClick={() => toggleAllRows()}\n              >\n                <AccordionToggleIcon\n                  accordionOpen={!!headerToggle}\n                  elementClosed={<VisaChevronRightTiny rtl />}\n                  elementOpen={<VisaChevronDownTiny />}\n                />\n              </Button>\n            </Td>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        {sortedData.map((row, rowIndex) => (\n          <Tbody key={rowIndex}>\n            <Tr className=\"v-accordion-heading\">\n              <Td className=\"compact-column\">\n                <Button\n                  aria-expanded={!!expandedRows[row[identifyingColumn]]}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  aria-labelledby={row[identifyingColumn] + '-id-multi-select'}\n                  onClick={() => toggleRow(row[identifyingColumn])}\n                >\n                  <AccordionToggleIcon\n                    accordionOpen={!!expandedRows[row[identifyingColumn]]}\n                    elementClosed={<VisaChevronRightTiny rtl />}\n                    elementOpen={<VisaChevronDownTiny />}\n                  />\n                </Button>\n              </Td>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  id={col.name === identifyingColumn ? row[identifyingColumn] + '-id-multi-select' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : <Typography variant=\"body-2\">{row[col.name]}</Typography>}\n                </Td>\n              ))}\n            </Tr>\n            <Tr>\n              <UtilityFragment vPaddingVertical={10} vHide={!expandedRows[row[identifyingColumn]]}>\n                <Td\n                  className=\"v-accordion-panel\"\n                  colSpan={columnData.length + 1}\n                  aria-hidden={!expandedRows[row[identifyingColumn]]}\n                  style={{ paddingInline: 'var(--v-accordion-panel-padding-inline)' }}\n                >\n                  {accordionData[row[identifyingColumn]]?.loading ? (\n                    <Utility vFlexGrow>\n                      <UtilityFragment vMarginVertical={8}>\n                        <ProgressLinear aria-label=\"Please wait\" id=\"data-fetch-accordion-progress\" />\n                      </UtilityFragment>\n                      <label className=\"v-progress-label v-sr\" htmlFor=\"data-fetch-accordion-progress\">\n                        <Utility tag=\"span\" role=\"alert\">\n                          Loading...\n                        </Utility>\n                      </label>\n                    </Utility>\n                  ) : accordionData[row[identifyingColumn]]?.data ? (\n                    <Utility>\n                      <UtilityFragment vMarginBottom={12}>\n                        <Typography variant=\"label-large-active\">Details for {row[identifyingColumn]}</Typography>\n                      </UtilityFragment>\n                      {accordionData[row[identifyingColumn]]?.data?.['Data'] && (\n                        <UtilityFragment vMarginBottom={12}>\n                          <Typography variant=\"body-2\">\n                            {accordionData[row[identifyingColumn]]?.data?.['Data']}\n                          </Typography>\n                        </UtilityFragment>\n                      )}\n                    </Utility>\n                  ) : (\n                    <>\n                      <Typography variant=\"label-large-active\">Row {row[identifyingColumn]}</Typography>\n                      <Typography variant=\"body-2\">Error loading expanded content.</Typography>\n                    </>\n                  )}\n                </Td>\n              </UtilityFragment>\n            </Tr>\n          </Tbody>\n        ))}\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default DataFetchOnAccordionToggleDynamicTable;\n"
          },
          "name": "Table with data fetch on accordion toggle"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table loading states",
          "url": {
            "iframe": "patterns/dynamic-table/data-fetch-on-pagination",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/data-fetch-on-pagination.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/data-fetch-on-pagination.tsx": "import {\n  calculateTotalPages,\n  ProgressCircular,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  usePagination,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { useEffect, useMemo, useState, type CSSProperties } from 'react';\nimport ActionsButton from './shared/actions-button';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport DynamicTablePagination from './shared/pagination-shared';\nimport './shared/dynamic-table.scss';\nimport { columnDataFilterDefaults } from './shared/generate-demo-data.utils';\nimport { getTablePage, type PaginatedResponse } from './shared/mock-table-api.utils';\n\n/**\n * Paginated table with mock server-side data fetching and client-side caching.\n */\nconst DataFetchOnPaginationDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = [...columnDataFilterDefaults];\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  // Pagination\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n  const [totalItems, setTotalItems] = useState(0);\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  const [visibleRows, setVisibleRows] = useState<RowData[]>([]);\n  const [loading, setLoading] = useState(false);\n\n  /**\n   * Client-side cache to avoid refetching already-loaded pages\n   */\n  const [cache, setCache] = useState<Map<string, PaginatedResponse>>(new Map());\n\n  // Create a cache key based on current page parameters\n  const cacheKey = useMemo(\n    () => `${currentPage}-${itemsPerPage}-${JSON.stringify(sortKey)}`,\n    [currentPage, itemsPerPage, sortKey]\n  );\n\n  /**\n   * Fetches data when pagination or sort changes, using client-side cache.\n   */\n  useEffect(() => {\n    getData();\n  }, [cacheKey]);\n\n  /**\n   * Fetches table data from API or cache.\n   */\n  const getData = async () => {\n    // Check if we already have this data cached\n    if (cache.has(cacheKey)) {\n      const cached = cache.get(cacheKey)!;\n      setVisibleRows(cached.data);\n      setTotalItems(cached.total);\n      return; // Skip API call - use cached data\n    }\n\n    // Data not in cache - fetch from API\n    setLoading(true);\n    const response = await getTablePage(currentPage, itemsPerPage, sortKey, columnData);\n\n    // Store response in cache for future use\n    setCache(new Map(cache).set(cacheKey, response));\n\n    setTotalItems(response.total);\n    setVisibleRows(response.data);\n    setLoading(false);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      {/* Dynamic table with action bar and pagination */}\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with action bar and pagination.</ScreenReader>\n          <Thead>\n            <Tr>\n              {columnData.map((col, index) => (\n                <Th\n                  key={index}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    <ActionsButton\n                      column={col}\n                      label={col.name}\n                      onSort={direction => sort(col, direction)}\n                      sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    />\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {loading ? (\n              <Tr>\n                <UtilityFragment vPaddingVertical={20} style={{ textAlign: 'center' }}>\n                  <Td colSpan={columnData.length}>\n                    <UtilityFragment vFlex vJustifyContent=\"center\">\n                      <ProgressCircular className=\"v-flex-grow\" indeterminate>\n                        <span className=\"v-sr\" role=\"alert\">\n                          Loading...\n                        </span>\n                      </ProgressCircular>\n                    </UtilityFragment>\n                  </Td>\n                </UtilityFragment>\n              </Tr>\n            ) : (\n              visibleRows.length > 0 &&\n              visibleRows.map((row, rowIndex) => (\n                <Tr key={rowIndex}>\n                  {columnData.map((col, colIndex) => (\n                    <Td\n                      key={colIndex}\n                      scope={col.identifier ? 'row' : undefined}\n                      className={col.compact ? 'compact-column' : ''}\n                      data-label={col.name}\n                    >\n                      {col.render ? col.render(row) : row[col.name]}\n                    </Td>\n                  ))}\n                </Tr>\n              ))\n            )}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n\n      {/* Shared pagination component */}\n      <DynamicTablePagination\n        id=\"dynamic-table-action-bar-and-pagination\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default DataFetchOnPaginationDynamicTable;\n"
          },
          "name": "Table with data fetch on pagination"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-select dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/multi-select",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/multi-select.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/multi-select.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport { Checkbox, ScreenReader, Table, TableWrapper, Tbody, Td, Th, Thead, Tr, Utility } from '@visa/nova-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Sortable data table with row selection and header checkbox for select all.\n * Displays indeterminate state when some rows are selected.\n */\nconst MultiSelectDynamicTable = () => {\n  /** Checkbox logic */\n  const [headerChecked, setHeaderChecked] = useState(false);\n  const [indeterminate, setIndeterminate] = useState(false);\n  const [checkedRows, setCheckedRows] = useState<Record<string, boolean>>({});\n\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(4, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Handles header checkbox change to select or unselect all rows.\n   *\n   * @param checked - Checked state of header checkbox\n   */\n  const onHeaderCheckboxChange = (checked: boolean) => {\n    // Update header checkbox state to reflect the new checked value\n    setHeaderChecked(checked);\n    // Clear indeterminate state since we're explicitly selecting all or none\n    setIndeterminate(false);\n\n    if (checked) {\n      // Build a new object with all row IDs mapped to true\n      const allCheckedRows: Record<string, boolean> = {};\n      sortedData.forEach(row => {\n        allCheckedRows[row[identifyingColumn] as string] = true;\n      });\n      // Update state with all rows selected\n      setCheckedRows(allCheckedRows);\n    } else {\n      // Clear the checked rows object to deselect everything\n      setCheckedRows({});\n    }\n  };\n\n  /**\n   * Handles individual row checkbox change.\n   *\n   * @param row - Row that was checked or unchecked\n   */\n  const onRowCheckboxChange = (row: RowData) => {\n    const rowId = row[identifyingColumn] as string;\n    const updatedCheckedRows = { ...checkedRows };\n\n    if (updatedCheckedRows[rowId]) {\n      // Row is currently checked, so uncheck it by removing from the object\n      delete updatedCheckedRows[rowId];\n    } else {\n      // Row is currently unchecked, so check it by adding to the object\n      updatedCheckedRows[rowId] = true;\n    }\n\n    // Update the checked rows state with the new selection\n    setCheckedRows(updatedCheckedRows);\n\n    // Calculate how many rows are now selected\n    const checkedCount = Object.keys(updatedCheckedRows).length;\n    const totalRows = sortedData.length;\n\n    // Update header checkbox state based on selection count\n    // Header is checked only if all rows are selected\n    setHeaderChecked(checkedCount === totalRows);\n    // Header is indeterminate if some (but not all) rows are selected\n    setIndeterminate(checkedCount > 0 && checkedCount < totalRows);\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n      >\n        <ScreenReader tag=\"caption\">Dynamic table with multi-select.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Td className=\"v-th compact-column\">\n              <Utility vAlignItems=\"center\" vFlex vGap={2}>\n                <Checkbox\n                  checked={headerChecked}\n                  indeterminate={indeterminate}\n                  aria-label={headerChecked ? 'Unselect all' : 'Select all'}\n                  onChange={event => onHeaderCheckboxChange(event.currentTarget.checked)}\n                  id=\"header-checkbox\"\n                />\n              </Utility>\n            </Td>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        <Tbody>\n          {sortedData.map((row, rowIndex) => (\n            <Tr key={rowIndex}>\n              <Td className=\"compact-column\">\n                <Utility vAlignItems=\"center\" vFlex vGap={2}>\n                  <Checkbox\n                    className=\"row-selection-checkbox\"\n                    checked={!!checkedRows[row[identifyingColumn] as string]}\n                    aria-label={\n                      checkedRows[row[identifyingColumn] as string]\n                        ? `Unselect ${row[identifyingColumn]}`\n                        : `Select ${row[identifyingColumn]}`\n                    }\n                    onChange={() => onRowCheckboxChange(row)}\n                    id={`checkbox-${rowIndex}`}\n                  />\n                </Utility>\n              </Td>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : row[col.name]}\n                </Td>\n              ))}\n            </Tr>\n          ))}\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default MultiSelectDynamicTable;\n"
          },
          "name": "Multi-select table"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/single-row-expandable",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/single-row-expandable.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/single-row-expandable.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport {\n  AccordionToggleIcon,\n  Button,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport ActionsButton from './shared/actions-button';\nimport './shared/dynamic-table.scss';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Accordion table where only one row expands at a time to show row details.\n */\nconst SingleRowExpandableDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(4, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // State for expanded row, only one can be expanded at a time\n  const [expandedRow, setExpandedRow] = useState<string | null>(null);\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Toggles expanded state of a row.\n   *\n   * @param name - Name of toggled row\n   */\n  const toggleRow = (name: string) => {\n    // toggle only the clicked row, close others\n    if (expandedRow === name) {\n      setExpandedRow(null);\n    } else {\n      setExpandedRow(name);\n    }\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        alternate\n        className=\"v-accordion accordion-style-table\"\n      >\n        <ScreenReader tag=\"caption\">Single row expandable table.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Td className=\"v-th compact-column\">\n              <span className=\"v-sr\">Expand or collapse row</span>\n            </Td>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        {sortedData.map((row, rowIndex) => (\n          <Tbody key={rowIndex}>\n            <Tr className=\"v-accordion-heading\">\n              <Td className=\"compact-column\">\n                <Button\n                  aria-expanded={expandedRow === row[identifyingColumn]}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  aria-labelledby={row[identifyingColumn] + '-id-single-row'}\n                  onClick={() => toggleRow(row[identifyingColumn] as string)}\n                >\n                  <AccordionToggleIcon\n                    accordionOpen={expandedRow === row[identifyingColumn]}\n                    elementClosed={<VisaChevronRightTiny rtl />}\n                    elementOpen={<VisaChevronDownTiny />}\n                  />\n                </Button>\n              </Td>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  id={col.name === identifyingColumn ? row[identifyingColumn] + '-id-single-row' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : <Typography variant=\"body-2\">{row[col.name]}</Typography>}\n                </Td>\n              ))}\n            </Tr>\n            <Tr>\n              <UtilityFragment vPaddingVertical={10} vHide={expandedRow !== row[identifyingColumn]}>\n                <Td\n                  className=\"v-accordion-panel\"\n                  colSpan={columnData.length + 1}\n                  aria-hidden={expandedRow !== row[identifyingColumn]}\n                  style={{ paddingInline: 'var(--v-accordion-panel-padding-inline)' }}\n                >\n                  <Typography variant=\"label-large-active\">Row {row[identifyingColumn]} expanded content</Typography>\n                  <Typography>This is an optional description with additional data.</Typography>\n                </Td>\n              </UtilityFragment>\n            </Tr>\n          </Tbody>\n        ))}\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default SingleRowExpandableDynamicTable;\n"
          },
          "name": "Single row expandable table"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Expandable dynamic tables",
          "url": {
            "iframe": "patterns/dynamic-table/multi-row-expandable",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/multi-row-expandable.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/multi-row-expandable.tsx": "import { useMemo, useState, type CSSProperties } from 'react';\nimport {\n  AccordionToggleIcon,\n  Button,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport './shared/dynamic-table.scss';\nimport ActionsButton from './shared/actions-button';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\n\n/**\n * Accordion table where multiple rows can expand simultaneously to show row details.\n */\nconst MultiRowExpandableDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(4, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // State for expanded rows\n  const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({});\n  // State for header toggle\n  const [headerToggle, setHeaderToggle] = useState(false);\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  /**\n   * Toggles individual row expansion state.\n   *\n   * @param name - Row name to toggle\n   */\n  const toggleRow = (name: string) => {\n    if (expandedRows[name]) {\n      const updatedExpandedRows = { ...expandedRows };\n      delete updatedExpandedRows[name];\n      setExpandedRows(updatedExpandedRows);\n    } else {\n      setExpandedRows({ ...expandedRows, [name]: true });\n    }\n\n    // Check if all rows are expanded after the toggle and update header toggle state\n    const allExpanded = Object.keys(expandedRows).length === sortedData.length;\n    setHeaderToggle(allExpanded);\n  };\n\n  /**\n   * Toggles all rows expansion state.\n   */\n  const toggleAllRows = () => {\n    const newToggleState = !headerToggle;\n    setHeaderToggle(newToggleState);\n\n    // Update all rows to match the header toggle state\n    if (newToggleState) {\n      const allExpandedRows: Record<string, boolean> = {};\n      sortedData.forEach(row => {\n        allExpandedRows[row[identifyingColumn] as string] = true;\n      });\n      console.log(allExpandedRows);\n      setExpandedRows(allExpandedRows);\n    } else {\n      setExpandedRows({});\n    }\n  };\n\n  return (\n    <TableWrapper>\n      <Table\n        style={\n          {\n            // Use compact spacing\n            '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n            '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n          } as CSSProperties\n        }\n        className=\"v-accordion accordion-style-table\"\n      >\n        <ScreenReader tag=\"caption\">Multi row expandable table.</ScreenReader>\n        <Thead>\n          <Tr>\n            <Td className=\"v-th compact-column\">\n              <Button\n                aria-expanded={!!headerToggle}\n                buttonSize=\"small\"\n                colorScheme=\"tertiary\"\n                iconButton\n                aria-label={headerToggle ? 'Collapse all rows' : 'Expand all rows'}\n                onClick={() => toggleAllRows()}\n              >\n                <AccordionToggleIcon\n                  accordionOpen={!!headerToggle}\n                  elementClosed={<VisaChevronRightTiny rtl />}\n                  elementOpen={<VisaChevronDownTiny />}\n                />\n              </Button>\n            </Td>\n            {columnData.map((col, index) => (\n              <Th\n                key={index}\n                scope=\"col\"\n                className={col.compact ? 'compact-column' : ''}\n                aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n              >\n                <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                  {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                  <ActionsButton\n                    column={col}\n                    label={col.name}\n                    onSort={direction => sort(col, direction)}\n                    sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                  />\n                </Utility>\n              </Th>\n            ))}\n          </Tr>\n        </Thead>\n        {sortedData.map((row, rowIndex) => (\n          <Tbody key={rowIndex}>\n            <Tr className=\"v-accordion-heading\">\n              <Td className=\"compact-column\">\n                <Button\n                  aria-expanded={!!expandedRows[row[identifyingColumn] as string]}\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  aria-labelledby={row[identifyingColumn] + '-id-multi-select'}\n                  onClick={() => toggleRow(row[identifyingColumn] as string)}\n                >\n                  <AccordionToggleIcon\n                    accordionOpen={!!expandedRows[row[identifyingColumn] as string]}\n                    elementClosed={<VisaChevronRightTiny rtl />}\n                    elementOpen={<VisaChevronDownTiny />}\n                  />\n                </Button>\n              </Td>\n              {columnData.map((col, colIndex) => (\n                <Td\n                  key={colIndex}\n                  scope={col.identifier ? 'row' : undefined}\n                  id={col.name === identifyingColumn ? row[identifyingColumn] + '-id-multi-select' : undefined}\n                  className={col.compact ? 'compact-column' : ''}\n                  data-label={col.name}\n                >\n                  {col.render ? col.render(row) : <Typography variant=\"body-2\">{row[col.name]}</Typography>}\n                </Td>\n              ))}\n            </Tr>\n            <Tr>\n              <UtilityFragment vPaddingVertical={10} vHide={!expandedRows[row[identifyingColumn] as string]}>\n                <Td\n                  className=\"v-accordion-panel\"\n                  colSpan={columnData.length + 1}\n                  aria-hidden={!expandedRows[row[identifyingColumn] as string]}\n                  style={{ paddingInline: 'var(--v-accordion-panel-padding-inline)' }}\n                >\n                  <Typography variant=\"label-large-active\">Row {row[identifyingColumn]} expanded content</Typography>\n                  <Typography>This is an optional description with additional data.</Typography>\n                </Td>\n              </UtilityFragment>\n            </Tr>\n          </Tbody>\n        ))}\n      </Table>\n    </TableWrapper>\n  );\n};\n\nexport default MultiRowExpandableDynamicTable;\n"
          },
          "name": "Multi-row expandable table"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/selection-based-action-bar",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/selection-based-action-bar.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/selection-based-action-bar.tsx": "import type { CSSProperties } from 'react';\nimport { VisaClearAltTiny, VisaFilterAltTiny, VisaSettingsTiny } from '@visa/nova-icons-react';\nimport { Button, Chip, Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Props for SelectionBasedActionBarDynamicTable.\n *\n * @property amountSelected - (optional) Number of rows currently selected\n * @property clearSelection - (optional) Function to clear all row selections\n */\ninterface SelectionBasedProps {\n  amountSelected?: number;\n  clearSelection?: () => void;\n}\n\n/**\n * Action bar that responds to row selections in a table.\n */\nconst SelectionBasedActionBarDynamicTable = ({ amountSelected = 0, clearSelection }: SelectionBasedProps) => {\n  return (\n    <UtilityFragment\n      vPaddingHorizontal={16}\n      vPaddingVertical={8}\n      style={\n        {\n          '--v-surface-background': 'var(--palette-default-surface-2)',\n          '--v-surface-border-radius': 'var(--size-rounded-none)',\n        } as CSSProperties\n      }\n    >\n      <Surface>\n        <Utility vFlex vFlexWrap vJustifyContent=\"between\" vAlignItems=\"center\" vGap={10}>\n          <Utility vFlex vGap=\"8\">\n            <Button>Primary action</Button>\n            <Button colorScheme=\"secondary\" disabled={amountSelected === 0}>\n              Secondary action\n            </Button>\n            <Button colorScheme=\"tertiary\" disabled={amountSelected === 0}>\n              Tertiary action\n            </Button>\n          </Utility>\n          <Utility vFlex vGap=\"8\">\n            {amountSelected > 0 && (\n              <Chip chipSize=\"compact\">\n                <span>{amountSelected} selected</span>\n                <Button\n                  onClick={clearSelection}\n                  aria-label=\"clear selected rows\"\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  subtle\n                >\n                  <VisaClearAltTiny />\n                </Button>\n              </Chip>\n            )}\n            <Button\n              iconButton\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              aria-label=\"filter table - selection-based action bar\"\n            >\n              <VisaFilterAltTiny />\n            </Button>\n            <Button\n              iconButton\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              aria-label=\"table settings - selection-based action bar\"\n            >\n              <VisaSettingsTiny />\n            </Button>\n          </Utility>\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n\nexport default SelectionBasedActionBarDynamicTable;\n"
          },
          "name": "Selection-based action bar"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/search-action-bar",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/search-action-bar.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/search-action-bar.tsx": "import { useEffect, useRef, useState, type CSSProperties, type FocusEvent } from 'react';\nimport { VisaClearAltTiny, VisaFilterAltTiny, VisaRefreshTiny, VisaSearchLow } from '@visa/nova-icons-react';\nimport { Button, Input, InputContainer, Surface, Typography, Utility, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Action bar with integrated search functionality.\n */\nconst SearchActionBarDynamicTable = () => {\n  const [showClearButton, setShowClearButton] = useState(false);\n  const [inputValue, setInputValue] = useState('');\n\n  const inputRef = useRef<HTMLInputElement>(null);\n\n  /**\n   * Hides clear button when focus leaves the input container.\n   *\n   * @param event - Focus event from input container\n   */\n  const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n    if (!event.currentTarget.contains(event.relatedTarget)) {\n      setShowClearButton(false);\n    }\n  };\n\n  /**\n   * Clears input value and refocuses the input field.\n   */\n  const handleClear = () => {\n    setInputValue('');\n    // Put focus back into the input\n    if (inputRef.current) {\n      inputRef.current.focus();\n    }\n  };\n\n  /**\n   * Shows or hides clear button based on input value.\n   */\n  useEffect(() => {\n    if (inputValue !== '') setShowClearButton(true);\n    else setShowClearButton(false);\n  }, [inputValue]);\n\n  return (\n    <UtilityFragment\n      vPaddingHorizontal={16}\n      vPaddingVertical={8}\n      style={\n        {\n          '--v-surface-background': 'var(--palette-default-surface-2)',\n          '--v-surface-border-radius': 'var(--size-rounded-none)',\n        } as CSSProperties\n      }\n    >\n      <Surface>\n        <Utility vFlex vJustifyContent=\"between\" vFlexWrap vAlignItems=\"center\" vGap={10}>\n          <Utility vFlex vGap=\"8\" vAlignItems=\"center\">\n            <Typography variant=\"headline-4\">Headline</Typography>\n            <Button buttonSize=\"small\" iconButton colorScheme=\"tertiary\" aria-label=\"refresh\">\n              <VisaRefreshTiny />\n            </Button>\n          </Utility>\n          <Utility vFlex vGap=\"8\" vAlignItems=\"center\">\n            <Utility vFlex vFlexCol vGap={4}>\n              <InputContainer\n                onBlur={e => handleBlur(e)}\n                onFocus={() => {\n                  if (inputValue !== '') setShowClearButton(true);\n                }}\n              >\n                <VisaSearchLow />\n                {/* padding logic prevents input from growing visually when clear button appears */}\n                <UtilityFragment vPaddingRight={!showClearButton ? 38 : 0}>\n                  <Input\n                    ref={inputRef}\n                    aria-required=\"true\"\n                    aria-label=\"Search\"\n                    onChange={e => setInputValue(e.currentTarget.value)}\n                    type=\"text\"\n                    value={inputValue}\n                    placeholder=\"Search\"\n                    name=\"search-action-bar\"\n                  />\n                </UtilityFragment>\n                {showClearButton && (\n                  <Button\n                    aria-label=\"Clear\"\n                    buttonSize=\"small\"\n                    colorScheme=\"tertiary\"\n                    iconButton\n                    onClick={handleClear}\n                    subtle\n                  >\n                    <VisaClearAltTiny />\n                  </Button>\n                )}\n              </InputContainer>\n            </Utility>\n            <Button iconButton buttonSize=\"small\" colorScheme=\"tertiary\" aria-label=\"filter table - search action bar\">\n              <VisaFilterAltTiny />\n            </Button>\n          </Utility>\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n\nexport default SearchActionBarDynamicTable;\n"
          },
          "name": "Search action bar"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/subtle-action-bar",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/subtle-action-bar.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/subtle-action-bar.tsx": "import type { CSSProperties } from 'react';\nimport { VisaFilterAltTiny } from '@visa/nova-icons-react';\nimport { Button, Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Minimal, unobtrusive action bar with no background.\n */\nconst SubtleActionBarDynamicTable = () => {\n  return (\n    <UtilityFragment\n      vPaddingHorizontal={16}\n      vPaddingVertical={8}\n      style={\n        {\n          // Use transparent background and no border for subtle action bar\n          '--v-surface-background': 'var(--palette-default-transparent)',\n          '--v-surface-border-size': '0px',\n        } as CSSProperties\n      }\n    >\n      <Surface>\n        <Utility vFlex vFlexWrap vGap=\"10\" vJustifyContent=\"end\" vAlignItems=\"center\">\n          <Button>Primary action</Button>\n          <Button iconButton buttonSize=\"small\" colorScheme=\"tertiary\" aria-label=\"filter table - subtle action bar\">\n            <VisaFilterAltTiny />\n          </Button>\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n\nexport default SubtleActionBarDynamicTable;\n"
          },
          "name": "Subtle action bar"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/toggle-action-bar",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/toggle-action-bar.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/toggle-action-bar.tsx": "import { useState, type CSSProperties } from 'react';\nimport {\n  VisaChevronDownTiny,\n  VisaChevronUpTiny,\n  VisaFilterAltTiny,\n  VisaMapLow,\n  VisaViewGridLow,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  DropdownButton,\n  DropdownMenu,\n  Listbox,\n  Surface,\n  Toggle,\n  ToggleContainer,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport {\n  useFloating,\n  offset,\n  flip,\n  shift,\n  autoUpdate,\n  useClick,\n  useDismiss,\n  useInteractions,\n  FloatingFocusManager,\n} from '@floating-ui/react';\nimport DropdownMenuButton from './shared/dropdown-menu-button';\n\nconst options = [\n  { label: 'Label 3', id: 'toggle-action-bar-label-3', icon: <VisaViewGridLow />, defaultSelected: true },\n  { label: 'Label 1', id: 'toggle-action-bar-label-1', icon: <VisaMapLow /> },\n];\n\n/**\n * Action bar with toggle buttons, dropdown action menu, and filter button.\n */\nconst ToggleActionBarDynamicTable = () => {\n  // State to track which toggle button is currently pressed\n  // Initialized as an array of booleans based on defaultSelected property\n  const [togglePressedState, setTogglePressedState] = useState(options.map(o => !!o.defaultSelected));\n\n  /**\n   * Handles single-select toggle press, ensuring only one toggle is active.\n   *\n   * @param pressedIndex - Index of pressed toggle button\n   */\n  const handleSingleSelectTogglePress = (pressedIndex: number) => {\n    setTogglePressedState(options.map((_, buttonIndex) => pressedIndex === buttonIndex));\n  };\n\n  // State to track whether the dropdown menu is open or closed\n  const [open, setOpen] = useState(false);\n\n  // useFloating hook manages positioning of the dropdown menu relative to the trigger button\n  // Returns context for other hooks, computed styles for positioning, and refs for elements\n  const {\n    context: context,\n    floatingStyles: floatingStyles,\n    refs: ref,\n  } = useFloating({\n    middleware: [offset(2), flip(), shift()], // Position 2px below, flip if no space, shift to stay in viewport\n    open: open,\n    placement: 'bottom-end', // Align dropdown to bottom-right of trigger button\n    onOpenChange: setOpen,\n    whileElementsMounted: autoUpdate, // Continuously update position while menu is open\n  });\n  // useClick hook enables opening/closing dropdown on click\n  const clickRef = useClick(context);\n  // useDismiss hook enables closing dropdown when clicking outside or pressing Escape\n  const dismissMenu = useDismiss(context);\n  // useInteractions hook combines multiple interaction behaviors and returns prop getters\n  const { getReferenceProps, getFloatingProps } = useInteractions([clickRef, dismissMenu]);\n  return (\n    <UtilityFragment\n      vPaddingHorizontal={16}\n      vPaddingVertical={8}\n      style={\n        {\n          '--v-surface-background': 'var(--palette-default-surface-2)',\n          '--v-surface-border-radius': 'var(--size-rounded-none)',\n        } as CSSProperties\n      }\n    >\n      <Surface>\n        <Utility vFlex vFlexWrap vJustifyContent=\"between\" vAlignItems=\"center\" vGap={10}>\n          <UtilityFragment>\n            <DropdownButton\n              aria-expanded={open}\n              aria-controls={open ? 'toggle-action-bar-label-dropdown-menu' : undefined}\n              ref={ref.setReference}\n              {...getReferenceProps()}\n            >\n              Action {open ? <VisaChevronUpTiny /> : <VisaChevronDownTiny />}\n            </DropdownButton>\n          </UtilityFragment>\n          {open && (\n            <FloatingFocusManager context={context} modal={false} restoreFocus={true} initialFocus={-1}>\n              <DropdownMenu\n                id={'toggle-action-bar-label-dropdown-menu'}\n                aria-hidden={!open}\n                style={\n                  {\n                    inlineSize: '180px',\n                    '--v-surface-background': 'var(--palette-default-surface-1)', // prevent inheriting from action bar's surface 2 background\n                    position: 'absolute',\n                    ...floatingStyles,\n                    zIndex: 3,\n                  } as CSSProperties\n                }\n                ref={ref.setFloating}\n                {...getFloatingProps()}\n              >\n                <Listbox>\n                  <DropdownMenuButton onClick={() => setOpen(false)}>Action 1</DropdownMenuButton>\n                  <DropdownMenuButton onClick={() => setOpen(false)}>Action 2</DropdownMenuButton>\n                  <DropdownMenuButton onClick={() => setOpen(false)}>Action 3</DropdownMenuButton>\n                </Listbox>\n              </DropdownMenu>\n            </FloatingFocusManager>\n          )}\n          <Utility vFlex vGap=\"8\" vAlignItems=\"center\">\n            <ToggleContainer>\n              {options.map((option, optionIndex) => (\n                <UtilityFragment key={option.id} vGap={6}>\n                  <Toggle\n                    tag=\"button\"\n                    aria-label={option.label}\n                    aria-pressed={togglePressedState[optionIndex]}\n                    onClick={() => handleSingleSelectTogglePress(optionIndex)}\n                  >\n                    {option.icon}\n                  </Toggle>\n                </UtilityFragment>\n              ))}\n            </ToggleContainer>\n            <Button iconButton buttonSize=\"small\" colorScheme=\"tertiary\" aria-label=\"filter table - toggle action bar\">\n              <VisaFilterAltTiny />\n            </Button>\n          </Utility>\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n\nexport default ToggleActionBarDynamicTable;\n"
          },
          "name": "Toggle action bar"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/pagination",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/pagination.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/pagination.tsx": "import {\n  calculatePagesFromTo,\n  calculateTotalPages,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  usePagination,\n  Utility,\n} from '@visa/nova-react';\nimport { useMemo, useState, type CSSProperties } from 'react';\nimport ActionsButton from './shared/actions-button';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport './shared/dynamic-table.scss';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\nimport DynamicTablePagination from './shared/pagination-shared';\n\n/**\n * Sortable data table with pagination controls for large datasets.\n */\nconst PaginationDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(300, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update based on sort key and data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  // Pagination state\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n\n  // Use useMemo for visible rows\n  const visibleRows = useMemo(() => {\n    const { from, to } = calculatePagesFromTo(sortedData.length, itemsPerPage, selectedPage);\n    return sortedData.slice(from - 1, to);\n  }, [sortedData, itemsPerPage, selectedPage]);\n\n  // Pagination\n  const totalItems = sortedData?.length ?? 0;\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      <TableWrapper>\n        <Table\n          style={\n            {\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with pagination.</ScreenReader>\n          <Thead>\n            <Tr>\n              {columnData.map((col, index) => (\n                <Th\n                  key={index}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={\n                    sortKey.column === col.name\n                      ? sortKey.direction === SortType.ASC\n                        ? 'ascending'\n                        : 'descending'\n                      : 'none'\n                  }\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    {col.sortable && (\n                      <ActionsButton\n                        column={col}\n                        label={col.name}\n                        sorted={sortKey.column === col.name ? sortKey.direction : undefined}\n                        onSort={direction => sort(col, direction)}\n                      />\n                    )}\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {visibleRows.map((row, rowIndex) => (\n              <Tr key={rowIndex}>\n                {columnData.map((col, colIndex) => (\n                  <Td\n                    key={colIndex}\n                    scope={col.identifier ? 'row' : undefined}\n                    className={col.compact ? 'compact-column' : ''}\n                    data-label={col.name}\n                  >\n                    {col.render ? col.render(row) : row[col.name]}\n                  </Td>\n                ))}\n              </Tr>\n            ))}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n      <DynamicTablePagination\n        id=\"dynamic-table-pagination\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default PaginationDynamicTable;\n"
          },
          "name": "Table with pagination"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table layouts",
          "url": {
            "iframe": "patterns/dynamic-table/action-bar-and-pagination",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/action-bar-and-pagination.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/action-bar-and-pagination.tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  calculatePagesFromTo,\n  calculateTotalPages,\n  Checkbox,\n  InputContainer,\n  InputControl,\n  Label,\n  ScreenReader,\n  Select,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  usePagination,\n  Utility,\n} from '@visa/nova-react';\nimport { useMemo, useState, type ChangeEvent, type CSSProperties, type JSX } from 'react';\nimport SearchActionBarDynamicTable from './search-action-bar';\nimport SelectionBasedActionBarDynamicTable from './selection-based-action-bar';\nimport ActionsButton from './shared/actions-button';\nimport { SortType, type ColData, type RowData, type SortKeyType } from './shared/dynamic-table.constants';\nimport './shared/dynamic-table.scss';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport { generateBasicData, getDefaultColumnData } from './shared/generate-demo-data.utils';\nimport DynamicTablePagination from './shared/pagination-shared';\nimport SubtleActionBarDynamicTable from './subtle-action-bar';\nimport ToggleActionBarDynamicTable from './toggle-action-bar';\n\n/**\n * Sortable data table with pagination and swappable action bars (selection, search, subtle, toggle).\n * Switching between action bars is for demo purposes only; in a real application, one action bar would be chosen.\n * Checkbox selection state is only included for the selection-based action bar and resets when switching bars.\n */\nconst ActionBarAndPaginationDynamicTable = () => {\n  // Generate demo data\n  const columnData: ColData[] = getDefaultColumnData();\n  const data: RowData[] = generateBasicData(300, columnData);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // State for sorting, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: identifyingColumn, direction: SortType.ASC });\n\n  // Store sorted data and update when sortKey or data changes\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(sortKey, columnData, data);\n  }, [sortKey, columnData, data]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction: direction });\n  };\n\n  // Pagination state and calculations\n  // State for number of items to display per page (default 10)\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n  const totalItems = sortedData?.length ?? 0;\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  // usePagination hook provides navigation functions for page controls\n  // Extracts onFirstPage separately as it's needed to reset page when items per page changes\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  // Calculate visible rows for current page\n  // Recomputes whenever sorted data, items per page, or selected page changes\n  const visibleRows = useMemo(() => {\n    // Calculate the range of items to display (from and to indices)\n    const { from, to } = calculatePagesFromTo(sortedData.length, itemsPerPage, selectedPage);\n    // Slice the sorted data to get only the rows for the current page\n    // Subtract 1 from 'from' because array indices are 0-based but calculatePagesFromTo returns 1-based\n    return sortedData.slice(from - 1, to);\n  }, [sortedData, itemsPerPage, selectedPage]);\n\n  // action bars\n  const actionBars = ['Selection-based', 'Subtle', 'Search', 'Toggle'];\n  const [option, setOption] = useState('Selection-based');\n\n  /** Checkbox logic */\n  const [headerChecked, setHeaderChecked] = useState(false);\n  const [indeterminate, setIndeterminate] = useState(false);\n  const [checkedRows, setCheckedRows] = useState<Record<string, boolean>>({});\n\n  /**\n   * Resets multi-select state when action bar option changes.\n   *\n   * @param e - Change event from select element\n   */\n  const handleChangeState = (e: ChangeEvent<HTMLSelectElement>) => {\n    setOption(e.target.value);\n    setCheckedRows({});\n    setHeaderChecked(false);\n    setIndeterminate(false);\n  };\n\n  /**\n   * Handles header checkbox change for selecting or deselecting all rows.\n   *\n   * @param checked - Checked state of the header checkbox\n   */\n  const onHeaderCheckboxChange = (checked: boolean) => {\n    setHeaderChecked(checked);\n    setIndeterminate(false);\n\n    if (checked) {\n      // select all rows\n      const allCheckedRows: Record<string, boolean> = {};\n      sortedData.forEach(row => {\n        allCheckedRows[row[identifyingColumn] as string] = true;\n      });\n      setCheckedRows(allCheckedRows);\n    } else {\n      // unselect all rows\n      setCheckedRows({});\n    }\n  };\n\n  /**\n   * Handles individual row checkbox change.\n   *\n   * @param row - Selected row\n   */\n  const onRowCheckboxChange = (row: RowData) => {\n    const rowId = row[identifyingColumn] as string;\n    const updatedCheckedRows = { ...checkedRows };\n\n    if (updatedCheckedRows[rowId]) {\n      delete updatedCheckedRows[rowId];\n    } else {\n      updatedCheckedRows[rowId] = true;\n    }\n\n    // Set updated checked rows\n    setCheckedRows(updatedCheckedRows);\n\n    // Update header checkbox state - checked and indeterminate\n    const checkedCount = Object.keys(updatedCheckedRows).length;\n    const totalRows = sortedData.length;\n\n    setHeaderChecked(checkedCount === totalRows);\n    setIndeterminate(checkedCount > 0 && checkedCount < totalRows);\n  };\n\n  // Action bar options, based on action bar examples available\n  const actionBarComponents: Record<string, JSX.Element> = {\n    Search: <SearchActionBarDynamicTable />,\n    Subtle: <SubtleActionBarDynamicTable />,\n    Toggle: <ToggleActionBarDynamicTable />,\n    'Selection-based': (\n      <SelectionBasedActionBarDynamicTable\n        amountSelected={Object.keys(checkedRows).length}\n        clearSelection={() => onHeaderCheckboxChange(false)}\n      />\n    ),\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      {/* Select field to choose action bar type for demo purposes */}\n      <Utility tag=\"fieldset\" vFlex vFlexCol vGap={6} vAlignSelf=\"start\">\n        <Label htmlFor=\"action-bar-select\">Action bar</Label>\n        <InputContainer>\n          <Select id=\"action-bar-select\" name=\"action-bar-select\" onChange={handleChangeState} value={option}>\n            <option hidden value=\"\" />\n            {actionBars.map((option, index) => (\n              <option key={`${option}-${index}`} value={option}>\n                {option}\n              </option>\n            ))}\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n      </Utility>\n\n      {/* Render selected action bar */}\n      {actionBarComponents[option] || null}\n\n      {/* Dynamic table with action bar and pagination */}\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with action bar and pagination.</ScreenReader>\n          <Thead>\n            <Tr>\n              {option === 'Selection-based' ? (\n                // If the selection-based action bar is chosen, render header checkbox\n                <Td className=\"v-th compact-column\">\n                  <Utility vAlignItems=\"center\" vFlex vGap={2}>\n                    <Checkbox\n                      checked={headerChecked}\n                      indeterminate={indeterminate}\n                      aria-label={headerChecked ? 'Unselect all' : 'Select all'}\n                      onChange={event => onHeaderCheckboxChange(event.currentTarget.checked)}\n                      id=\"header-checkbox-action-bar-and-pagination\"\n                    />\n                  </Utility>\n                </Td>\n              ) : null}\n              {columnData.map((col, index) => (\n                <Th\n                  key={index}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    <ActionsButton\n                      column={col}\n                      label={col.name}\n                      onSort={direction => sort(col, direction)}\n                      sorted={col.name === sortKey.column ? sortKey.direction : SortType.NONE}\n                    />\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {visibleRows.map((row, rowIndex) => (\n              <Tr key={rowIndex}>\n                {option === 'Selection-based' ? (\n                  // If the selection-based action bar is chosen, render row checkbox\n                  <Td className=\"compact-column\">\n                    <Utility vAlignItems=\"center\" vFlex vGap={2}>\n                      <Checkbox\n                        className=\"row-selection-checkbox\"\n                        checked={!!checkedRows[row[identifyingColumn] as string]}\n                        aria-label={\n                          checkedRows[row[identifyingColumn] as string]\n                            ? `Unselect ${row[identifyingColumn]}`\n                            : `Select ${row[identifyingColumn]}`\n                        }\n                        onChange={() => onRowCheckboxChange(row)}\n                        id={`checkbox-${rowIndex}`}\n                      />\n                    </Utility>\n                  </Td>\n                ) : null}\n                {columnData.map((col, colIndex) => (\n                  <Td\n                    key={colIndex}\n                    scope={col.identifier ? 'row' : undefined}\n                    className={col.compact ? 'compact-column' : ''}\n                    data-label={col.name}\n                  >\n                    {col.render ? col.render(row) : row[col.name]}\n                  </Td>\n                ))}\n              </Tr>\n            ))}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n\n      {/* Shared pagination component */}\n      <DynamicTablePagination\n        id=\"dynamic-table-action-bar-and-pagination\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default ActionBarAndPaginationDynamicTable;\n"
          },
          "name": "Table with action bar and pagination"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table with filters",
          "url": {
            "iframe": "patterns/dynamic-table/filter-dialog",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/filter-dialog.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/filter-dialog.tsx": "import { VisaFilterAltTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  calculatePagesFromTo,\n  calculateTotalPages,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  usePagination,\n  Utility,\n} from '@visa/nova-react';\nimport { useEffect, useMemo, useState, type CSSProperties } from 'react';\nimport AccordionFilterItem from './shared/accordion-filter-items';\nimport FilterActionBar from './shared/action-bar';\nimport ActionsButton from './shared/actions-button';\nimport ChipFilters from './shared/chip-filters';\nimport { SortType, type ColData, type FilterableTableState, type RowData } from './shared/dynamic-table.constants';\nimport './shared/dynamic-table.scss';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport FilterCheckboxGroups from './shared/filter-checkbox-groups';\nimport {\n  applyAllFilters,\n  clearMultipleFilters,\n  clearSingleFilter,\n  generateFilterData,\n  getFilteredData,\n} from './shared/filters.utils';\nimport { columnDataFilterDefaults } from './shared/generate-demo-data.utils';\nimport DynamicTablePagination from './shared/pagination-shared';\nimport TableDropdownButton from './shared/table-dropdown-button';\n\n/**\n * Props for ActionBar component.\n *\n * @property open - Whether the filter dialog is currently open\n * @property setOpen - Function to control the dialog open state\n * @property columnData - Array of column configuration objects\n * @property applyFilters - Function to apply all selected filters to the table\n * @property clearFilters - Function to clear all active filters\n */\ninterface ActionBarProps {\n  open: boolean;\n  setOpen: (value: boolean) => void;\n  columnData: ColData[];\n  applyFilters: () => void;\n  clearFilters: () => void;\n}\n\n/**\n * Filter dialog for applying filters across multiple columns simultaneously. The dialog\n * presents all filterable columns in an organized accordion layout, allowing users to\n * configure multiple filters before applying them at once.\n */\nconst ActionBar = ({ open, setOpen, columnData, applyFilters, clearFilters }: ActionBarProps) => {\n  return (\n    <FilterActionBar>\n      <TableDropdownButton\n        id=\"filter-dialog\"\n        buttonAriaLabel=\"Filter table\"\n        open={!!open}\n        setOpen={(isOpen: boolean) => {\n          setOpen(isOpen);\n        }}\n        icon={<VisaFilterAltTiny />}\n      >\n        <Utility vFlex vFlexCol vGap={10} vFlexGrow vPadding={7}>\n          <Typography variant=\"headline-4\">All filters</Typography>\n          <Utility vFlex vFlexCol vGap=\"4\" vFlexGrow>\n            {columnData.map(\n              column =>\n                column.headerActions && (\n                  <AccordionFilterItem\n                    filterLength={column.headerActions.selectedOptions.length}\n                    columnName={column.name}\n                    key={'accordion-filter-dialog-item-' + column.name}\n                  >\n                    <FilterCheckboxGroups column={column} key={'filter-dialog-checkbox-group' + column.name} />\n                  </AccordionFilterItem>\n                )\n            )}\n          </Utility>\n          <Utility vFlex vJustifyContent=\"between\" vGap=\"16\">\n            <Button onClick={() => applyFilters()}>Apply</Button>\n            <Button colorScheme=\"tertiary\" onClick={() => clearFilters()}>\n              Clear all\n            </Button>\n          </Utility>\n        </Utility>\n      </TableDropdownButton>\n    </FilterActionBar>\n  );\n};\n\n/**\n * Table with centralized filter controls in a dialog interface.\n */\nconst FilterDialogDynamicTable = () => {\n  // Generate demo data\n  const [columnData, setColumnData] = useState<ColData[]>(() => [...columnDataFilterDefaults]);\n  const data: RowData[] = generateFilterData(100);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  const [tableState, setTableState] = useState<FilterableTableState>({\n    column: identifyingColumn,\n    direction: SortType.ASC,\n    filters: {},\n  });\n\n  // holds sorted data (ascending, descending, none)\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(tableState, columnData, data);\n  }, [tableState]);\n  // holds filtered data\n  const filteredData = useMemo(() => {\n    return getFilteredData(tableState.filters, sortedData);\n  }, [tableState.filters, sortedData]);\n\n  // Pagination state\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n\n  // holds visible rows based on pagination (computed after filter)\n  const visibleRows = useMemo(() => {\n    const { from, to } = calculatePagesFromTo(filteredData.length, itemsPerPage, selectedPage);\n    return filteredData.slice(from - 1, to);\n  }, [filteredData, itemsPerPage, selectedPage]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setTableState({ ...tableState, column: column.name, direction: direction });\n    onFirstPage();\n  };\n\n  /**\n   * Resets to first page when filters change.\n   */\n  useEffect(() => {\n    setSelectedPage(1);\n  }, [filteredData]);\n\n  // Pagination\n  const totalItems = useMemo(() => filteredData?.length ?? 0, [filteredData]);\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  /** Filtering */\n  const [filterPopupOpen, setFilterPopupOpen] = useState<boolean>(false);\n\n  /**\n   * Applies filters from dialog to table state.\n   */\n  const applyFilters = () => {\n    const updatedFilters = applyAllFilters(columnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    setFilterPopupOpen(false);\n  };\n\n  /**\n   * Clears all filters from table state.\n   *\n   * @param closeDropdown - Whether to close dialog after clearing\n   */\n  const clearFilters = (closeDropdown = true) => {\n    const { updatedColumnData, updatedFilters } = clearMultipleFilters(columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    if (closeDropdown) {\n      setFilterPopupOpen(false);\n    }\n  };\n\n  /**\n   * Clears a single filter from table state.\n   *\n   * @param filterName - Name of filter to clear\n   */\n  const clearFilter = (filterName: string) => {\n    const { updatedColumnData, updatedFilters } = clearSingleFilter(filterName, columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      <ActionBar\n        open={filterPopupOpen}\n        setOpen={setFilterPopupOpen}\n        columnData={columnData}\n        applyFilters={applyFilters}\n        clearFilters={clearFilters}\n      />\n      <ChipFilters\n        filters={tableState.filters}\n        clearSingleFilter={clearFilter}\n        clearAllFilters={() => clearFilters(false)}\n      />\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // Use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with filter dialog.</ScreenReader>\n          <Thead>\n            <Tr>\n              {columnData.map(col => (\n                <Th\n                  key={'filter-dialog-th-' + col.name.replace(/\\s+/g, '-').toLowerCase()}\n                  scope=\"col\"\n                  className={col.compact ? 'compact-column' : ''}\n                  aria-sort={col.name === tableState.column ? tableState.direction : 'none'}\n                >\n                  <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                    {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                    <ActionsButton\n                      column={col}\n                      label={col.name}\n                      sortOnly={col.sortable}\n                      onSort={direction => sort(col, direction)}\n                      sorted={col.name === tableState.column ? tableState.direction : SortType.NONE}\n                    />\n                  </Utility>\n                </Th>\n              ))}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {visibleRows.map((row, rowIndex) => (\n              <Tr key={rowIndex + '-filter-dialog'}>\n                {columnData.map(col => (\n                  <Td\n                    key={'filter-dialog-td-' + col.name.replace(/\\s+/g, '-').toLowerCase()}\n                    scope={col.identifier ? 'row' : undefined}\n                    className={col.compact ? 'compact-column' : ''}\n                    data-label={col.name}\n                  >\n                    {col.render ? col.render(row) : row[col.name]}\n                  </Td>\n                ))}\n              </Tr>\n            ))}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n      <DynamicTablePagination\n        id=\"dynamic-table-filter-dialog\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default FilterDialogDynamicTable;\n"
          },
          "name": "Table with filter dialog"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table with filters",
          "url": {
            "iframe": "patterns/dynamic-table/in-table-filters",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/in-table-filters.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/in-table-filters.tsx": "import { VisaSettingsTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  calculatePagesFromTo,\n  calculateTotalPages,\n  Checkbox,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  usePagination,\n  Utility,\n} from '@visa/nova-react';\nimport cn from 'clsx';\nimport { useEffect, useMemo, useState, type CSSProperties, type Dispatch, type SetStateAction } from 'react';\nimport FilterActionBar from './shared/action-bar';\nimport ActionsButton from './shared/actions-button';\nimport ChipFilters from './shared/chip-filters';\nimport { SortType, type ColData, type FilterableTableState, type RowData } from './shared/dynamic-table.constants';\nimport './shared/dynamic-table.scss';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport {\n  applyAllFilters,\n  clearMultipleFilters,\n  clearSingleFilter,\n  generateFilterData,\n  getFilteredData,\n  handleColumnVisibilityChange,\n  manageColumnVisibility,\n  resetTable,\n  toggleColumnDropdown,\n} from './shared/filters.utils';\nimport { columnDataFilterDefaults } from './shared/generate-demo-data.utils';\nimport DynamicTablePagination from './shared/pagination-shared';\nimport TableDropdownButton from './shared/table-dropdown-button';\n\n/**\n * Props for ActionBar component.\n *\n * @property columnData - Array of column configuration objects\n * @property hiddenColumns - Array of booleans indicating hidden state of columns\n * @property setHiddenColumns - Function to update hidden columns state\n * @property setColumnData - Function to update column configuration\n * @property setTableState - Function to update table state including sort and filters\n */\ninterface ActionBarProps {\n  columnData: ColData[];\n  hiddenColumns: boolean[];\n  setHiddenColumns: Dispatch<SetStateAction<boolean[]>>;\n  setColumnData: Dispatch<SetStateAction<ColData[]>>;\n  setTableState: Dispatch<SetStateAction<FilterableTableState>>;\n}\n\n/**\n * Table settings and column visibility management.\n */\nconst ActionBar = ({ columnData, hiddenColumns, setHiddenColumns, setColumnData, setTableState }: ActionBarProps) => {\n  // State for settings dropdown open/closed\n  const [settingsDropdownOpen, setSettingsDropdownOpen] = useState<boolean>(false);\n\n  /**\n   * Applies column visibility changes.\n   */\n  const handleApply = () => {\n    manageColumnVisibility(columnData, hiddenColumns, setColumnData);\n    setSettingsDropdownOpen(false);\n  };\n\n  /**\n   * Resets table to default state.\n   */\n  const reset = () => {\n    setHiddenColumns(columnData.map(() => false));\n    resetTable(columnData, setColumnData, setTableState, setSettingsDropdownOpen);\n  };\n\n  return (\n    <FilterActionBar>\n      <TableDropdownButton\n        id=\"in-table-filters\"\n        buttonAriaLabel=\"In-table filter settings\"\n        open={!!settingsDropdownOpen}\n        setOpen={setSettingsDropdownOpen}\n        icon={<VisaSettingsTiny />}\n      >\n        <Utility vFlex vFlexCol vGap={6} vFlexGrow vMargin={7}>\n          <fieldset>\n            <Label id=\"in-table-filters-legend\" tag=\"legend\">\n              Show columns\n            </Label>\n            <ListboxContainer>\n              <Listbox scroll tag=\"div\">\n                {columnData.map((column, index) => {\n                  {\n                    /* Don't allow compact or identifier columns to be hidden */\n                  }\n                  return !column.identifier && !column.compact ? (\n                    <ListboxItem<'label'>\n                      htmlFor={`in-table-filters-option-${index}`}\n                      key={`in-table-filters-option-${index}`}\n                      tag=\"label\"\n                    >\n                      <Checkbox\n                        checked={!hiddenColumns[index]}\n                        className=\"v-flex-shrink-0\"\n                        id={`in-table-filters-option-${index}`}\n                        name={`in-table-filters-option-${index}`}\n                        onChange={() =>\n                          handleColumnVisibilityChange(column, hiddenColumns, columnData, setHiddenColumns)\n                        }\n                      />\n                      <Label tag=\"span\">{column.name}</Label>\n                    </ListboxItem>\n                  ) : null;\n                })}\n              </Listbox>\n            </ListboxContainer>\n            {columnData.filter(col => col.hidden).length > 0 && (\n              <InputMessage id=\"manage-columns-in-table-amount\">\n                {columnData.filter(col => col.hidden).length} column(s) hidden\n              </InputMessage>\n            )}\n          </fieldset>\n          <Utility vFlex vMarginTop={8} vGap={10} vJustifyContent=\"between\">\n            <Button onClick={handleApply}>Apply</Button>\n            <Button colorScheme=\"tertiary\" onClick={reset}>\n              Reset table\n            </Button>\n          </Utility>\n        </Utility>\n      </TableDropdownButton>\n    </FilterActionBar>\n  );\n};\n\n/**\n * Table with inline filtering controls within column headers.\n */\nconst InTableFiltersDynamicTable = () => {\n  // Generate demo data - deep copy to avoid shared state with other examples\n  const [columnData, setColumnData] = useState<ColData[]>(() =>\n    columnDataFilterDefaults.map(col => ({\n      ...col,\n      headerActions: col.headerActions ? { ...col.headerActions, selectedOptions: [] } : col.headerActions,\n    }))\n  );\n  const data: RowData[] = generateFilterData(100);\n\n  // State for pinned column, default to Column D\n  const [pinnedColumn, setPinnedColumn] = useState<ColData | null>(null);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // visible columns based on hidden/pinned state\n  const visibleColumns = useMemo(() => {\n    const nonHiddenColumns = columnData.filter(col => !col.hidden);\n    if (pinnedColumn) {\n      return [pinnedColumn, ...nonHiddenColumns.filter(col => col.name !== pinnedColumn.name)];\n    }\n    return nonHiddenColumns;\n  }, [columnData, pinnedColumn]);\n\n  // track open state of column filter dropdowns\n  const [columnFiltersOpen, setColumnFiltersOpen] = useState<boolean[]>(columnData.map(() => false));\n\n  // Table state for sorting and filtering\n  const [tableState, setTableState] = useState<FilterableTableState>({\n    column: identifyingColumn,\n    direction: SortType.ASC,\n    filters: {},\n  });\n\n  // initial full data set\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(tableState, columnData, data);\n  }, [tableState]);\n\n  // holds filtered data\n  const filteredData = useMemo(() => {\n    return getFilteredData(tableState.filters, sortedData);\n  }, [tableState.filters, sortedData]);\n\n  // Pagination state\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n\n  // holds visible rows based on pagination (computed after filter)\n  const visibleRows = useMemo(() => {\n    const { from, to } = calculatePagesFromTo(filteredData.length, itemsPerPage, selectedPage);\n    return filteredData.slice(from - 1, to);\n  }, [filteredData, itemsPerPage, selectedPage]);\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setTableState({ ...tableState, column: column.name, direction: direction });\n    onFirstPage();\n  };\n\n  /**\n   * Resets to first page when filters change.\n   */\n  useEffect(() => {\n    setSelectedPage(1);\n  }, [filteredData]);\n\n  // Pagination\n  const totalItems = useMemo(() => filteredData?.length ?? 0, [filteredData]);\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  // State for hidden columns\n  const [hiddenColumns, setHiddenColumns] = useState<boolean[]>(columnData.map(col => !!col.hidden));\n\n  /**\n   * Clears a single filter from table state.\n   *\n   * @param filterName - Name of filter to clear\n   */\n  const clearFilter = (filterName: string) => {\n    const { updatedColumnData, updatedFilters } = clearSingleFilter(filterName, columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n  };\n\n  /**\n   * Applies filters from column to table state.\n   *\n   * @param column - Column containing filters to apply\n   */\n  const applyColumnFilters = (column: ColData) => {\n    const updatedFilters = applyAllFilters(columnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    toggleColumnHeaderAction(column);\n  };\n\n  /**\n   * Clears all filters from table state.\n   *\n   * @param column - Optional column to close dropdown\n   * @param closeDropdown - Whether to close dropdown after clearing\n   */\n  const clearColumnFilters = (column?: ColData, closeDropdown = true) => {\n    const { updatedColumnData, updatedFilters } = clearMultipleFilters(columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    if (closeDropdown && column) {\n      toggleColumnHeaderAction(column);\n    }\n  };\n\n  /**\n   * Toggles column header action dropdown open/closed state.\n   *\n   * @param column - Column to toggle dropdown for\n   * @param isOpen - Whether dropdown should be open\n   */\n  const toggleColumnHeaderAction = (column: ColData, isOpen = false) => {\n    const colIndex = columnData.indexOf(column);\n    toggleColumnDropdown(colIndex, columnFiltersOpen, setColumnFiltersOpen, isOpen);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      <ActionBar\n        columnData={columnData}\n        hiddenColumns={hiddenColumns}\n        setHiddenColumns={setHiddenColumns}\n        setColumnData={setColumnData}\n        setTableState={setTableState}\n      />\n      <ChipFilters\n        filters={tableState.filters}\n        clearSingleFilter={clearFilter}\n        clearAllFilters={() => clearColumnFilters(undefined, false)}\n      />\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // Use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n          className=\"fixed-table\"\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with in-table filters.</ScreenReader>\n          <Thead>\n            <Tr>\n              {visibleColumns.map(col => {\n                const columnName = col.name.replace(/\\s+/g, '-').toLowerCase();\n                return (\n                  <Th\n                    key={'th-' + columnName}\n                    scope=\"col\"\n                    className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                    aria-sort={col.name === tableState.column ? tableState.direction : SortType.NONE}\n                  >\n                    <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                      {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                      <ActionsButton\n                        column={col}\n                        label={col.name}\n                        onSort={direction => sort(col, direction)}\n                        sorted={col.name === tableState.column ? tableState.direction : SortType.NONE}\n                        open={columnFiltersOpen[columnData.indexOf(col)]}\n                        setOpen={(isOpen: boolean) => {\n                          toggleColumnHeaderAction(col, isOpen);\n                        }}\n                        pinned={col.name === pinnedColumn?.name}\n                        onPin={() => {\n                          setPinnedColumn(prev => {\n                            if (prev && prev === col) {\n                              // unpin the column\n                              return null;\n                            } else {\n                              // pin the new column\n                              return col;\n                            }\n                          });\n                          const index = columnData.indexOf(col);\n                          toggleColumnDropdown(index, columnFiltersOpen, setColumnFiltersOpen);\n                        }}\n                        onHide={() => {\n                          handleColumnVisibilityChange(col, hiddenColumns, columnData, setHiddenColumns, setColumnData);\n                        }}\n                        applyColumnFilters={column => applyColumnFilters(column)}\n                        clearColumnFilters={column => clearColumnFilters(column)}\n                      />\n                    </Utility>\n                  </Th>\n                );\n              })}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {visibleRows.map((row, rowIndex) => (\n              <Tr key={rowIndex}>\n                {visibleColumns.map(col => (\n                  <Td\n                    key={'td-' + col.name.replace(/\\s+/g, '-').toLowerCase()}\n                    scope={col.identifier ? 'row' : undefined}\n                    className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                    data-label={col.name}\n                  >\n                    {col.render ? col.render(row) : row[col.name]}\n                  </Td>\n                ))}\n              </Tr>\n            ))}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n      <DynamicTablePagination\n        id=\"dynamic-table-in-table-filters\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default InTableFiltersDynamicTable;\n"
          },
          "name": "Table with in-table filters"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Dynamic table with filters",
          "url": {
            "iframe": "patterns/dynamic-table/filters",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/filters.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/dynamic-table/filters.tsx": "import { VisaFilterAltTiny, VisaSettingsTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  calculatePagesFromTo,\n  calculateTotalPages,\n  Checkbox,\n  InputMessage,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  ScreenReader,\n  Table,\n  TableWrapper,\n  Tbody,\n  Td,\n  Th,\n  Thead,\n  Tr,\n  Typography,\n  usePagination,\n  Utility,\n} from '@visa/nova-react';\nimport { useEffect, useMemo, useState, type CSSProperties, type Dispatch, type SetStateAction } from 'react';\nimport { SortType, type ColData, type FilterableTableState, type RowData } from './shared/dynamic-table.constants';\n\nimport cn from 'clsx';\nimport AccordionFilterItem from './shared/accordion-filter-items';\nimport FilterActionBar from './shared/action-bar';\nimport ActionsButton from './shared/actions-button';\nimport ChipFilters from './shared/chip-filters';\nimport './shared/dynamic-table.scss';\nimport { revisedSortTableData } from './shared/dynamic-table.utils';\nimport FilterCheckboxGroups from './shared/filter-checkbox-groups';\nimport {\n  applyAllFilters,\n  applySingleColumnFilter,\n  clearMultipleFilters,\n  clearSingleFilter,\n  generateFilterData,\n  getFilteredData,\n  handleColumnVisibilityChange,\n  manageColumnVisibility,\n  resetTable,\n  toggleColumnDropdown,\n} from './shared/filters.utils';\nimport { columnDataFilterDefaults } from './shared/generate-demo-data.utils';\nimport DynamicTablePagination from './shared/pagination-shared';\nimport TableDropdownButton from './shared/table-dropdown-button';\n\n/**\n * Props for ActionBar component.\n *\n * @property filterDropdownOpen - Whether the filter dropdown is currently open\n * @property setFilterDropdownOpen - Function to open or close the filter dropdown\n * @property columnData - Array of column data\n * @property hiddenColumns - Array of booleans indicating which columns are hidden\n * @property setHiddenColumns - Function to update which columns are hidden\n * @property setColumnData - Function to update column settings\n * @property setTableState - Function to update table sorting and filters\n * @property applyFilters - Function to apply all selected filters\n * @property clearFilters - Function to clear all filters\n */\ninterface ActionBarProps {\n  filterDropdownOpen: boolean;\n  setFilterDropdownOpen: (value: boolean) => void;\n  columnData: ColData[];\n  hiddenColumns: boolean[];\n  setHiddenColumns: Dispatch<SetStateAction<boolean[]>>;\n  setColumnData: Dispatch<SetStateAction<ColData[]>>;\n  setTableState: Dispatch<SetStateAction<FilterableTableState>>;\n  applyFilters: () => void;\n  clearFilters: () => void;\n}\n\n/**\n * ActionBar combines both filter management and table settings in a unified location.\n * It provides a filter dialog for applying filters across multiple columns\n * simultaneously, plus a settings dropdown for managing column visibility.\n */\nconst ActionBar = ({\n  filterDropdownOpen,\n  setFilterDropdownOpen,\n  columnData,\n  hiddenColumns,\n  setHiddenColumns,\n  setColumnData,\n  setTableState,\n  applyFilters,\n  clearFilters,\n}: ActionBarProps) => {\n  // State for settings dropdown open, separate from filter dropdown (which lives in parent)\n  const [settingsDropdownOpen, setSettingsDropdownOpen] = useState<boolean>(false);\n\n  /**\n   * Saves column visibility changes and closes the settings dropdown.\n   */\n  const handleApply = () => {\n    manageColumnVisibility(columnData, hiddenColumns, setColumnData);\n    setSettingsDropdownOpen(false);\n  };\n\n  /**\n   * Resets table to its default state.\n   */\n  const reset = () => {\n    setHiddenColumns(columnData.map(() => false));\n    resetTable(columnData, setColumnData, setTableState, setSettingsDropdownOpen);\n  };\n\n  return (\n    // Filter dropdown\n    <FilterActionBar>\n      <TableDropdownButton\n        id=\"all-filters\"\n        buttonAriaLabel=\"Filter table\"\n        open={!!filterDropdownOpen}\n        setOpen={(isOpen: boolean) => {\n          setFilterDropdownOpen(isOpen);\n        }}\n        icon={<VisaFilterAltTiny />}\n      >\n        <Utility vFlex vFlexCol vGap={10} vFlexGrow vPadding={7}>\n          <Typography variant=\"headline-4\">All filters</Typography>\n          <Utility vFlex vFlexCol vGap=\"4\" vFlexGrow>\n            {columnData.map(\n              column =>\n                column.headerActions && (\n                  <AccordionFilterItem\n                    filterLength={column.headerActions.selectedOptions.length}\n                    columnName={column.name}\n                    key={'accordion-all-filter-item-' + column.name}\n                  >\n                    <FilterCheckboxGroups column={column} key={'all-filter-checkbox-group' + column.name} />\n                  </AccordionFilterItem>\n                )\n            )}\n          </Utility>\n          <Utility vFlex vJustifyContent=\"between\" vGap=\"16\">\n            <Button onClick={() => applyFilters()}>Apply</Button>\n            <Button colorScheme=\"tertiary\" onClick={() => clearFilters()}>\n              Clear all\n            </Button>\n          </Utility>\n        </Utility>\n      </TableDropdownButton>\n\n      {/* Settings dropdown */}\n      <TableDropdownButton\n        id=\"multiple-filters-settings\"\n        buttonAriaLabel=\"All filter table settings\"\n        open={!!settingsDropdownOpen}\n        setOpen={(isOpen: boolean) => {\n          setSettingsDropdownOpen(isOpen);\n        }}\n        icon={<VisaSettingsTiny />}\n      >\n        <Utility vFlex vFlexCol vGap={6} vFlexGrow vMargin={7}>\n          <fieldset>\n            <Label id=\"all-filters-legend\" tag=\"legend\">\n              Show columns\n            </Label>\n            <ListboxContainer>\n              <Listbox scroll tag=\"div\">\n                {columnData.map((column, index) => {\n                  {\n                    /* Don't allow compact or identifier columns to be hidden */\n                  }\n                  return !column.identifier && !column.compact ? (\n                    <ListboxItem<'label'>\n                      htmlFor={`all-filters-option-${index}`}\n                      key={`all-filters-option-${index}`}\n                      tag=\"label\"\n                    >\n                      <Checkbox\n                        checked={!hiddenColumns[index]}\n                        className=\"v-flex-shrink-0\"\n                        id={`all-filters-option-${index}`}\n                        name={`all-filters-option-${index}`}\n                        onChange={() =>\n                          handleColumnVisibilityChange(column, hiddenColumns, columnData, setHiddenColumns)\n                        }\n                      />\n                      <Label tag=\"span\">{column.name}</Label>\n                    </ListboxItem>\n                  ) : null;\n                })}\n              </Listbox>\n            </ListboxContainer>\n            {columnData.filter(col => col.hidden).length > 0 && (\n              <InputMessage id=\"manage-columns-all-filters-amount\">\n                {columnData.filter(col => col.hidden).length} column(s) hidden\n              </InputMessage>\n            )}\n          </fieldset>\n          <Utility vFlex vMarginTop={8} vGap={10} vJustifyContent=\"between\">\n            <Button onClick={handleApply}>Apply</Button>\n            <Button colorScheme=\"tertiary\" onClick={reset}>\n              Reset table\n            </Button>\n          </Utility>\n        </Utility>\n      </TableDropdownButton>\n    </FilterActionBar>\n  );\n};\n\n/**\n * Advanced table with comprehensive filtering, column management, and pagination.\n */\nconst FiltersDynamicTable = () => {\n  // Generate demo data - deep copy to avoid shared state with other examples\n  const [columnData, setColumnData] = useState<ColData[]>(() =>\n    columnDataFilterDefaults.map(col => ({\n      ...col,\n      headerActions: col.headerActions ? { ...col.headerActions, selectedOptions: [] } : col.headerActions,\n    }))\n  );\n  const data: RowData[] = generateFilterData(100);\n\n  // State for pinned column, default to Column D\n  const [pinnedColumn, setPinnedColumn] = useState<ColData | null>(null);\n\n  // Determine identifying column, default to first column if none marked as identifier\n  const identifyingColumn = columnData.find(col => col.identifier)?.name || columnData[0].name;\n\n  // visible columns based on hidden state\n  const visibleColumns = useMemo(() => {\n    const nonHiddenColumns = columnData.filter(col => !col.hidden);\n    if (pinnedColumn) {\n      return [pinnedColumn, ...nonHiddenColumns.filter(col => col.name !== pinnedColumn.name)];\n    }\n    return nonHiddenColumns;\n  }, [columnData, pinnedColumn]);\n\n  const [columnFiltersOpen, setColumnFiltersOpen] = useState<boolean[]>(columnData.map(() => false));\n\n  const [tableState, setTableState] = useState<FilterableTableState>({\n    column: identifyingColumn,\n    direction: SortType.ASC,\n    filters: {},\n  });\n\n  // holds sorted data (ascending, descending, none)\n  const sortedData = useMemo(() => {\n    return revisedSortTableData(tableState, columnData, data);\n  }, [tableState]);\n\n  // holds filtered data, updates when filters or sorted data change\n  const filteredData = useMemo(() => {\n    return getFilteredData(tableState.filters, sortedData);\n  }, [tableState.filters, sortedData]);\n\n  useEffect(() => {\n    // Reset to first page when filters change\n    setSelectedPage(1);\n  }, [filteredData]);\n\n  /**\n   * Sorts the table by a column and returns to the first page.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setTableState({ ...tableState, column: column.name, direction: direction });\n    onFirstPage();\n  };\n\n  // Pagination state\n  const [itemsPerPage, setItemsPerPage] = useState(10);\n  const [selectedPage, setSelectedPage] = useState(1);\n\n  // holds visible rows based on pagination (computed after filter)\n  const visibleRows = useMemo(() => {\n    const { from, to } = calculatePagesFromTo(filteredData.length, itemsPerPage, selectedPage);\n    return filteredData.slice(from - 1, to);\n  }, [filteredData, itemsPerPage, selectedPage]);\n\n  // Pagination\n  const totalItems = useMemo(() => filteredData?.length ?? 0, [filteredData]);\n  const totalPages = calculateTotalPages(totalItems, itemsPerPage);\n  const currentPage = selectedPage;\n  const { onFirstPage, ...remainingPaginationData } = usePagination({\n    selectedPage: currentPage,\n    setSelectedPage: setSelectedPage,\n    totalPages,\n  });\n\n  /** Filter, hide/show columns, pin columns */\n  const [hiddenColumns, setHiddenColumns] = useState<boolean[]>(columnData.map(col => !!col.hidden));\n  const [filterDropdownOpen, setFilterDropdownOpen] = useState<boolean>(false);\n\n  /**\n   * Applies selected filters and closes the filter dropdown.\n   */\n  const applyFilters = () => {\n    const updatedFilters = applyAllFilters(columnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    setFilterDropdownOpen(false);\n  };\n\n  /**\n   * Removes all filters from the table.\n   *\n   * @param closeDropdown - Whether to close the filter dropdown after clearing\n   */\n  const clearFilters = (closeDropdown = true) => {\n    const { updatedColumnData, updatedFilters } = clearMultipleFilters(columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    if (closeDropdown) setFilterDropdownOpen(false);\n  };\n\n  /**\n   * Removes a single filter from the table.\n   *\n   * @param filterName - Name of the filter to remove\n   */\n  const clearFilter = (filterName: string) => {\n    const { updatedColumnData, updatedFilters } = clearSingleFilter(filterName, columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n  };\n\n  /**\n   * Applies filters for a specific column from the column header dropdown.\n   *\n   * @param column - Column to apply filters for\n   */\n  const applyColumnFilters = (column: ColData) => {\n    const updatedFilters = applySingleColumnFilter(column);\n    setTableState({ ...tableState, filters: updatedFilters });\n    toggleColumnHeaderAction(column);\n  };\n\n  /**\n   * Removes filters for a specific column from the column header dropdown.\n   *\n   * @param column - Column to clear filters for\n   */\n  const clearColumnFilters = (column: ColData) => {\n    const { updatedColumnData, updatedFilters } = clearMultipleFilters(columnData);\n    setColumnData(updatedColumnData);\n    setTableState({ ...tableState, filters: updatedFilters });\n    toggleColumnHeaderAction(column);\n  };\n\n  /**\n   * Opens or closes the column header dropdown menu.\n   *\n   * @param column - Column to toggle dropdown for\n   * @param isOpen - Whether the dropdown should be open\n   */\n  const toggleColumnHeaderAction = (column: ColData, isOpen = false) => {\n    const colIndex = columnData.indexOf(column);\n    toggleColumnDropdown(colIndex, columnFiltersOpen, setColumnFiltersOpen, isOpen);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap=\"16\">\n      <ActionBar\n        filterDropdownOpen={filterDropdownOpen}\n        setFilterDropdownOpen={setFilterDropdownOpen}\n        columnData={columnData}\n        hiddenColumns={hiddenColumns}\n        setHiddenColumns={setHiddenColumns}\n        setColumnData={setColumnData}\n        setTableState={setTableState}\n        applyFilters={applyFilters}\n        clearFilters={clearFilters}\n      />\n      <ChipFilters\n        filters={tableState.filters}\n        clearSingleFilter={clearFilter}\n        clearAllFilters={() => clearFilters(false)}\n      />\n      <TableWrapper>\n        <Table\n          style={\n            {\n              // Use compact spacing\n              '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n              '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n            } as CSSProperties\n          }\n          alternate\n          className=\"fixed-table\"\n        >\n          <ScreenReader tag=\"caption\">Dynamic table with multiple filters.</ScreenReader>\n          <Thead>\n            <Tr>\n              {visibleColumns.map(col => {\n                const columnName = col.name.replace(/\\s+/g, '-').toLowerCase();\n                return (\n                  <Th\n                    key={'th-' + columnName}\n                    scope=\"col\"\n                    className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                    aria-sort={col.name === tableState.column ? tableState.direction : 'none'}\n                  >\n                    <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                      {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                      <ActionsButton\n                        column={col}\n                        label={col.name}\n                        onSort={direction => sort(col, direction)}\n                        sorted={col.name === tableState.column ? tableState.direction : SortType.NONE}\n                        open={columnFiltersOpen[columnData.indexOf(col)]}\n                        setOpen={(isOpen: boolean) => {\n                          toggleColumnHeaderAction(col, isOpen);\n                        }}\n                        pinned={col.name === pinnedColumn?.name}\n                        onPin={() => {\n                          setPinnedColumn(prev => {\n                            if (prev && prev === col) {\n                              // unpin the column\n                              return null;\n                            } else {\n                              // pin the new column\n                              return col;\n                            }\n                          });\n                          toggleColumnHeaderAction(col);\n                        }}\n                        onHide={() => {\n                          handleColumnVisibilityChange(col, hiddenColumns, columnData, setHiddenColumns, setColumnData);\n                          toggleColumnHeaderAction(col);\n                        }}\n                        applyColumnFilters={column => applyColumnFilters(column)}\n                        clearColumnFilters={column => clearColumnFilters(column)}\n                      />\n                    </Utility>\n                  </Th>\n                );\n              })}\n            </Tr>\n          </Thead>\n          <Tbody>\n            {visibleRows.map((row, rowIndex) => (\n              <Tr key={rowIndex}>\n                {visibleColumns.map(col => (\n                  <Td\n                    key={'td-' + col.name.replace(/\\s+/g, '-').toLowerCase()}\n                    scope={col.identifier ? 'row' : undefined}\n                    className={cn(col.compact && 'compact-column', col.name === pinnedColumn?.name && 'pinned-column')}\n                    data-label={col.name}\n                  >\n                    {col.render ? col.render(row) : row[col.name]}\n                  </Td>\n                ))}\n              </Tr>\n            ))}\n          </Tbody>\n        </Table>\n      </TableWrapper>\n      <DynamicTablePagination\n        id=\"dynamic-table-multiple-filters\"\n        onFirstPage={onFirstPage}\n        onItemsPerPageChange={setItemsPerPage}\n        page={currentPage}\n        pageSize={itemsPerPage}\n        showItemsPerPage={!!visibleRows.length}\n        totalCount={totalItems}\n        {...remainingPaginationData}\n      />\n    </Utility>\n  );\n};\n\nexport default FiltersDynamicTable;\n"
          },
          "name": "Table with multiple filter layouts"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/accordion-filter-items.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/accordion-filter-items.tsx": "import { VisaChevronRightTiny, VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionToggleIcon,\n  UtilityFragment,\n  AccordionPanel,\n  Badge,\n} from '@visa/nova-react';\n\n/**\n * Props for AccordionFilterItem.\n *\n * @property columnName - Name of the column being filtered\n * @property children - (optional) Filter options to display inside the accordion\n * @property filterLength - Number of active filters to display in the badge\n */\ninterface AccordionFilterItemProps {\n  columnName: string;\n  children?: React.ReactNode;\n  filterLength: number;\n}\n\n/**\n * Wraps filter options in an expandable accordion. It displays the column name with a badge\n * showing how many filters are active, and expands when clicked to reveal the filter options.\n */\nconst AccordionFilterItem = ({ columnName, children, filterLength }: AccordionFilterItemProps) => {\n  const id = `filter-accordion-${columnName.replace(/\\s+/g, '-').toLowerCase()}`;\n  return (\n    <>\n      <Accordion key={'accordion-item-' + id}>\n        <UtilityFragment vAlignItems=\"center\">\n          <AccordionHeading buttonSize=\"large\" colorScheme=\"secondary\" id={`${id}-panel-title`}>\n            <AccordionToggleIcon elementClosed={<VisaChevronRightTiny rtl />} elementOpen={<VisaChevronDownTiny />} />\n            {columnName}\n            {filterLength > 0 && (\n              <UtilityFragment vMarginLeft={'auto'}>\n                <Badge badgeType=\"critical\" badgeVariant=\"number\">\n                  {filterLength}\n                </Badge>\n              </UtilityFragment>\n            )}\n          </AccordionHeading>\n        </UtilityFragment>\n        <UtilityFragment vPadding={2}>\n          <AccordionPanel>{children}</AccordionPanel>\n        </UtilityFragment>\n      </Accordion>\n    </>\n  );\n};\n\nexport default AccordionFilterItem;\n"
          },
          "name": "Accordion filter items"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/action-bar.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/action-bar.tsx": "import React, { type CSSProperties } from 'react';\nimport { UtilityFragment, Surface, Utility, Button } from '@visa/nova-react';\n\n/**\n * Props for FilterActionBar.\n *\n * @property children - (optional) Additional action buttons to display on the right side of the action bar\n * @property className - (optional) Custom style name for appearance customization\n */\ninterface FilterActionBarProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\n/**\n * Standard action bar layout for table filtering examples. It displays primary, secondary,\n * and tertiary action buttons on the left, with additional custom buttons (like filter and\n * settings) on the right. This creates a consistent appearance across all dynamic table\n * examples that include action bars.\n */\nconst FilterActionBar: React.FC<FilterActionBarProps> = ({ children }) => (\n  <UtilityFragment\n    vPaddingHorizontal={16}\n    vPaddingVertical={8}\n    style={\n      {\n        '--v-surface-background': 'var(--palette-default-surface-2)',\n        '--v-surface-border-radius': 'var(--size-rounded-none)',\n      } as CSSProperties\n    }\n  >\n    <Surface>\n      <Utility vFlex vFlexWrap vJustifyContent=\"between\" vAlignItems=\"center\" vGap={10}>\n        <Utility vFlex vGap=\"8\">\n          <Button>Primary action</Button>\n          <Button colorScheme=\"secondary\">Secondary action</Button>\n          <Button colorScheme=\"tertiary\">Tertiary action</Button>\n        </Utility>\n        <Utility vFlex vGap=\"8\">\n          {children}\n        </Utility>\n      </Utility>\n    </Surface>\n  </UtilityFragment>\n);\n\nexport default FilterActionBar;\n"
          },
          "name": "Action bar"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/actions-button.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/actions-button.tsx": "import {\n  VisaOptionHorizontalTiny,\n  VisaOptionVerticalTiny,\n  VisaPasswordHideTiny,\n  VisaPinFillTiny,\n  VisaPinOutlineTiny,\n  VisaSortAscendingTiny,\n  VisaSortDescendingTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Divider, Listbox, Utility } from '@visa/nova-react';\nimport { useId, useState } from 'react';\nimport DropdownMenuButton from './dropdown-menu-button';\nimport { SortType, type ColData } from './dynamic-table.constants';\nimport FilterCheckboxGroups from './filter-checkbox-groups';\nimport SortIcon from './sort-icon';\nimport TableDropdownButton from './table-dropdown-button';\n\n/**\n * Props for ActionsButton.\n *\n * @property sortOnly - (optional) Whether to display only sort functionality without additional actions\n * @property label - Accessible label for the button\n * @property column - (optional) Column information including settings\n * @property open - (optional) Whether the dropdown menu is currently open\n * @property setOpen - (optional) Function to open or close the dropdown\n * @property sorted - (optional) Current sort direction for the column, if column is provided\n * @property onSort - (optional) Function called when sort direction changes\n * @property pinned - (optional) Whether the column is currently pinned, if column is provided\n * @property onPin - (optional) Function called when column pin state changes\n * @property includeHide - (optional) Whether to include the hide column option, if column is provided\n * @property onHide - (optional) Function called when column is hidden\n * @property applyColumnFilters - (optional) Function that applies the selected filters for the column\n * @property clearColumnFilters - (optional) Function that removes all filters from the column\n */\ninterface ActionsButtonProps {\n  sortOnly?: boolean;\n  label: string;\n  column?: ColData;\n  open?: boolean;\n  setOpen?: (open: boolean) => void;\n  sorted?: SortType;\n  onSort?: (sort: SortType) => void;\n  pinned?: boolean | null;\n  onPin?: () => void;\n  includeHide?: boolean;\n  onHide?: () => void;\n  applyColumnFilters?: (column: ColData) => void;\n  clearColumnFilters?: (column: ColData) => void;\n}\n\n/**\n * Versatile dropdown button component that provides actions for table columns or rows.\n * It can display sorting options, column pinning, visibility controls, and filtering\n * capabilities. The component adapts its display based on the provided props, showing\n * only relevant actions for the current context.\n */\nconst ActionsButton = ({\n  sortOnly = false,\n  label,\n  column,\n  open,\n  setOpen,\n  sorted,\n  onSort,\n  pinned = null,\n  onPin,\n  onHide,\n  applyColumnFilters,\n  clearColumnFilters,\n}: ActionsButtonProps) => {\n  const [localOpen, setLocalOpen] = useState(false);\n  const id = useId();\n\n  // Check if column has filter options\n  const includeFilters = column?.headerActions && column.headerActions.options.length > 0;\n\n  // Determine if we should render just a simple sort button (no dropdown)\n  // This happens when sortOnly is explicitly set, or when the column is sortable\n  // but has no other actions configured (no filters, pin, hide, or generic actions)\n  const renderSortOnly =\n    sortOnly ||\n    (!(column?.headerActions || column?.genericHeaderActions || onHide || onPin || includeFilters) && column?.sortable);\n\n  /**\n   * Closes the dropdown menu.\n   * Uses the parent component's close function if available, otherwise manages closing on its own.\n   */\n  const closeDropdown = () => {\n    column ? setOpen && setOpen(false) : setLocalOpen(false);\n  };\n\n  return (\n    <>\n      {column && renderSortOnly ? (\n        <Button\n          iconButton\n          buttonSize=\"small\"\n          colorScheme=\"tertiary\"\n          aria-label={`Sort by ${label} ${sorted === SortType.ASC ? 'descending' : 'ascending'}`}\n          onClick={() => {\n            onSort && onSort(sorted === SortType.ASC ? SortType.DESC : SortType.ASC);\n          }}\n        >\n          <SortIcon sorted={sorted} />\n        </Button>\n      ) : !column?.compact ? (\n        // <!-- Add padding to unsorted column so width doesn't change when sort icon appears -->\n        <Utility\n          vFlex\n          vJustifyContent=\"between\"\n          vAlignItems=\"center\"\n          vFlexGrow\n          vPaddingLeft={column && sorted === SortType.NONE ? 16 : 0}\n        >\n          {sorted === SortType.ASC || sorted === SortType.DESC ? <SortIcon sorted={sorted} /> : null}\n          {(setOpen || !column) && (\n            <TableDropdownButton\n              id={id}\n              open={column ? !!open : !!localOpen}\n              setOpen={() => {\n                closeDropdown();\n                column ? setOpen && setOpen(!open) : setLocalOpen(!localOpen);\n              }}\n              icon={column ? <VisaOptionHorizontalTiny /> : <VisaOptionVerticalTiny />}\n              buttonAriaLabel={label ? `more actions for ${label}` : 'more actions'}\n            >\n              {!column ? (\n                <Listbox>\n                  {\n                    // generic actions for a row action button\n                    [1, 2, 3, 4].map(item => (\n                      <>\n                        <DropdownMenuButton onClick={closeDropdown} key={`${item}-${id}`}>\n                          Action {item}\n                        </DropdownMenuButton>\n                        {item === 2 ? <Divider dividerType=\"decorative\" key={`divider-${item}-${id}`} /> : null}\n                      </>\n                    ))\n                  }\n                </Listbox>\n              ) : (\n                // specific actions for a column header\n                <Utility vFlex vFlexCol vPadding={4} vFlexGrow>\n                  {/* first set of actions  */}\n                  <Listbox>\n                    {column?.sortable ? (\n                      <>\n                        <DropdownMenuButton\n                          disabled={sorted === SortType.ASC}\n                          onClick={() => {\n                            closeDropdown();\n                            onSort && onSort(SortType.ASC);\n                          }}\n                        >\n                          <VisaSortAscendingTiny /> Sort ascending\n                        </DropdownMenuButton>\n                        <DropdownMenuButton\n                          disabled={sorted === SortType.DESC}\n                          onClick={() => {\n                            closeDropdown();\n                            onSort && onSort(SortType.DESC);\n                          }}\n                        >\n                          <VisaSortDescendingTiny /> Sort descending\n                        </DropdownMenuButton>\n                      </>\n                    ) : (\n                      <>\n                        <DropdownMenuButton onClick={closeDropdown}>Action 1</DropdownMenuButton>\n                        <DropdownMenuButton onClick={closeDropdown}>Action 2</DropdownMenuButton>\n                      </>\n                    )}\n                  </Listbox>\n                  <Divider dividerType=\"decorative\" />\n                  {/* second set of actions  */}\n                  <Listbox>\n                    {onPin && pinned !== null ? (\n                      <DropdownMenuButton\n                        onClick={() => {\n                          closeDropdown();\n                          onPin && onPin();\n                        }}\n                      >\n                        {pinned ? (\n                          <>\n                            <VisaPinOutlineTiny /> Unpin column\n                          </>\n                        ) : (\n                          <>\n                            <VisaPinFillTiny /> Pin column\n                          </>\n                        )}\n                      </DropdownMenuButton>\n                    ) : (\n                      <DropdownMenuButton onClick={closeDropdown}>Action 3</DropdownMenuButton>\n                    )}\n                    {/* Don't allow compact or identifier columns to be hidden */}\n                    {!column.compact && !column.identifier ? (\n                      onHide ? (\n                        <DropdownMenuButton\n                          onClick={() => {\n                            closeDropdown();\n                            onHide && onHide();\n                          }}\n                        >\n                          <VisaPasswordHideTiny />\n                          {`Hide column`}\n                        </DropdownMenuButton>\n                      ) : (\n                        <DropdownMenuButton onClick={closeDropdown}>Action 4</DropdownMenuButton>\n                      )\n                    ) : undefined}\n                  </Listbox>\n                  {includeFilters && column && applyColumnFilters && clearColumnFilters ? (\n                    <>\n                      <Divider dividerType=\"decorative\" />\n                      <FilterCheckboxGroups\n                        column={column}\n                        legend={column.name}\n                        closeDropdown={closeDropdown}\n                        applyColumnFilters={applyColumnFilters}\n                        clearColumnFilters={clearColumnFilters}\n                      />\n                    </>\n                  ) : null}\n                </Utility>\n              )}\n            </TableDropdownButton>\n          )}\n        </Utility>\n      ) : null}\n    </>\n  );\n};\n\nexport default ActionsButton;\n"
          },
          "name": "Actions button"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/badge.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/badge.tsx": "import React from 'react';\nimport { Badge } from '@visa/nova-react';\nimport { badgeConfigs } from './dynamic-table.constants';\n\n/**\n * Props for StatusBadge.\n *\n * @property label - Status value to display, mapped to corresponding badge configuration\n */\ninterface StatusBadgeProps {\n  label: string | boolean;\n}\n\n/**\n * StatusBadge renders a badge with appropriate styling and icon based on the provided\n * label. It maps status values to predefined badge configurations, automatically selecting\n * the correct badge type (success, warning, critical, etc.) and associated icon.\n */\nconst StatusBadge: React.FC<StatusBadgeProps> = ({ label }) => {\n  const badge = badgeConfigs.find(config => config.text === label) ?? badgeConfigs[2]; // default to 'stable' if not found\n  return (\n    <Badge badgeType={badge.type}>\n      {badge.icon}\n      {badge.text}\n    </Badge>\n  );\n};\n\nexport default StatusBadge;\n"
          },
          "name": "Badge"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/chip-filters.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/chip-filters.tsx": "import { VisaClearAltTiny } from '@visa/nova-icons-react';\nimport { Utility, Chip, Button, Typography, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Props for ChipFilters.\n *\n * @property filters - Currently applied filters grouped by column name\n * @property clearSingleFilter - Function to remove one specific filter\n * @property clearAllFilters - Function to remove all filters\n */\nexport interface ChipFiltersProps {\n  filters: Record<string, string[]>;\n  clearSingleFilter: (filterName: string) => void;\n  clearAllFilters: () => void;\n}\n\n/**\n * Displays applied filters as dismissible chips, allowing users to see which filters\n * are active and quickly remove them. It groups filters by column and provides both\n * individual filter removal and a \"Clear all\" action.\n */\nconst ChipFilters = ({ filters, clearSingleFilter, clearAllFilters }: ChipFiltersProps) => {\n  const flattenedFilters = Object.values(filters).flat();\n\n  /**\n   * Prevents form submission.\n   *\n   * @param event - Form event\n   */\n  const handleFormSubmit = (event: React.FormEvent) => {\n    event.preventDefault();\n  };\n\n  return (\n    flattenedFilters.length > 0 && (\n      <form aria-labelledby=\"in-table-filters-applied-form-label\" onSubmit={handleFormSubmit}>\n        <Utility vFlex vFlexWrap vGap={8} vAlignItems=\"center\">\n          <Typography variant=\"label-active\" id=\"in-table-filters-applied-form-label\" tag=\"span\">\n            Filters applied:\n          </Typography>\n          {Object.keys(filters).map(columnName => {\n            const filtersForColumn = filters[columnName];\n            return (\n              filtersForColumn.length > 0 && (\n                <fieldset key={columnName}>\n                  <legend className=\"v-sr\">{`Filters applied for ${columnName}`}</legend>\n                  <UtilityFragment vFlex vFlexWrap vGap={8}>\n                    <ul>\n                      {filtersForColumn.map((filterValue, index) => (\n                        <li key={`${columnName}-filter-${index}`}>\n                          <Chip>\n                            {filterValue}\n                            <Button\n                              type=\"button\"\n                              iconButton\n                              colorScheme=\"tertiary\"\n                              subtle\n                              aria-label={`Clear ${filterValue} filter for ${columnName}`}\n                              onClick={() => clearSingleFilter(filterValue)}\n                            >\n                              <VisaClearAltTiny />\n                            </Button>\n                          </Chip>\n                        </li>\n                      ))}\n                    </ul>\n                  </UtilityFragment>\n                </fieldset>\n              )\n            );\n          })}\n          <Button type=\"button\" onClick={clearAllFilters} colorScheme=\"tertiary\">\n            Clear all\n          </Button>\n        </Utility>\n      </form>\n    )\n  );\n};\n\nexport default ChipFilters;\n"
          },
          "name": "Chip filters"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/dropdown-menu-button.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/dropdown-menu-button.tsx": "import React, { type ReactNode } from 'react';\nimport { Button, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Props for DropdownMenuButton.\n *\n * @property children - Content to display within the button, typically text or icons\n * @property disabled - (optional) Whether the button is disabled and cannot be interacted with\n * @property onClick - (optional) Function called when the button is clicked\n */\ninterface DropdownMenuButtonProps {\n  children: ReactNode;\n  disabled?: boolean;\n  onClick?: () => void;\n}\n\n/**\n * Consistently styled button for use within dropdown menus throughout the table examples.\n * It ensures proper spacing, styling, and interaction states for menu items in column\n * headers, action bars, and other dropdown contexts.\n */\nconst DropdownMenuButton: React.FC<DropdownMenuButtonProps> = ({ children, disabled, onClick }) => {\n  return (\n    <li>\n      <UtilityFragment vFlex vFlexRow vJustifyContent=\"start\" vGap={6} vPaddingHorizontal={8} vPaddingVertical={11}>\n        <Button\n          className=\"v-listbox-item\"\n          colorScheme=\"tertiary\"\n          subtle\n          onClick={onClick ? onClick : undefined}\n          disabled={disabled ? disabled : undefined}\n        >\n          {children}\n        </Button>\n      </UtilityFragment>\n    </li>\n  );\n};\n\nexport default DropdownMenuButton;\n"
          },
          "name": "Dropdown menu button"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/dynamic-table-data.json"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/dynamic-table-data.json": "[\n  {\n    \"File name\": \"A1-100\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"640 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\",\n    \"Data\": \"High-resolution bitmap images for North America marketing campaign.\"\n  },\n  {\n    \"File name\": \"B2-101\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"999 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-102\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"852 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-103\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"133 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-104\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"154 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-105\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"666 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-106\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"860 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-107\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"436 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\",\n    \"Data\": \"PowerPoint presentation deck for South American market expansion strategy.\"\n  },\n  {\n    \"File name\": \"B2-108\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"588 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-109\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"232 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-110\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"292 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-111\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"157 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-112\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"332 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-113\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"501 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-114\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"239 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\",\n    \"Data\": \"Animated banner advertisement for European digital campaign.\"\n  },\n  {\n    \"File name\": \"B2-115\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"763 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-116\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"549 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-117\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"455 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-118\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"381 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-119\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"593 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-120\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"772 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-121\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"315 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\",\n    \"Data\": \"Compressed archive containing localized product documentation for Asia Pacific markets.\"\n  },\n  {\n    \"File name\": \"B2-122\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"861 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-123\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"196 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-124\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"230 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-125\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"983 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-126\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"427 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-127\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"816 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-128\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"796 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-129\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"786 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-130\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"287 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-131\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"772 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-132\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"232 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-133\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"318 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-134\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"503 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-135\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"483 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-136\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"582 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-137\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"128 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-138\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"806 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-139\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"854 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-140\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"781 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-141\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"735 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-142\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"512 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-143\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"502 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-144\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"129 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-145\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"141 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-146\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"854 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-147\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"932 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-148\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"137 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-149\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"698 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-150\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"486 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-151\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"326 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-152\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"298 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-153\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"643 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-154\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"155 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-155\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"609 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-156\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"550 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-157\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"334 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-158\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"283 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-159\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"222 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-160\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"719 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-161\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"357 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-162\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"994 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-163\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"217 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-164\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"288 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-165\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"955 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-166\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"482 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-167\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"937 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-168\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"214 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-169\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"991 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-170\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"653 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-171\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"745 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-172\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"498 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-173\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"341 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-174\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"961 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-175\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"350 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-176\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"155 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-177\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"860 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-178\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"950 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-179\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"135 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-180\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"739 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-181\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"808 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-182\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"785 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-183\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"859 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-184\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"553 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-185\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"317 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-186\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"498 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-187\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"261 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-188\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"278 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-189\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"273 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-190\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"414 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-191\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"616 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-192\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"663 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-193\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"204 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-194\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"433 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-195\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"761 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-196\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"227 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-197\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"510 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-198\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"302 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-199\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"811 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-200\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"687 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-201\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"888 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-202\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"156 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-203\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"643 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-204\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"136 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-205\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"446 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-206\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"569 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-207\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"521 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-208\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"735 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-209\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"351 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-210\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"536 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-211\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"167 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-212\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"571 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-213\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"431 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-214\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"558 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-215\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"308 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-216\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"179 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-217\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"369 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-218\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"940 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-219\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"361 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-220\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"844 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-221\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"536 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-222\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"313 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-223\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"611 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-224\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"763 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-225\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"942 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-226\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"279 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-227\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"382 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-228\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"989 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-229\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"668 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-230\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"140 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-231\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"145 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-232\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"662 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-233\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"661 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-234\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"192 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-235\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"643 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-236\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"937 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-237\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"640 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-238\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"939 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-239\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"459 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-240\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"968 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-241\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"124 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-242\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"249 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-243\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"812 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-244\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"652 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-245\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"869 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-246\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"641 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-247\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"164 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-248\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"551 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-249\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"133 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-250\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"172 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-251\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"761 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-252\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"822 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-253\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"864 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-254\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"714 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-255\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"304 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-256\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"952 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-257\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"928 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-258\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"376 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-259\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"494 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-260\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"215 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-261\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"796 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-262\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"632 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-263\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"349 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-264\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"698 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-265\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"205 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-266\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"356 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-267\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"208 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-268\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"962 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-269\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"281 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-270\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"517 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-271\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"334 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-272\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"385 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-273\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"351 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-274\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"276 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-275\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"244 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-276\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"110 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-277\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"453 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-278\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"117 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-279\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"630 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-280\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"296 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-281\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"656 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-282\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"201 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-283\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"107 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-284\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"650 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-285\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"684 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-286\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"993 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-287\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"590 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-288\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"373 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-289\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"965 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-290\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"995 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-291\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"361 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-292\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"461 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-293\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"460 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-294\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"239 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-295\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"683 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-296\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"886 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-297\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"195 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-298\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"505 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-299\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"236 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-300\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"791 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-301\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"306 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-302\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"849 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-303\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"865 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-304\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"750 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-305\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"124 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-306\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"932 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-307\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"587 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-308\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"773 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-309\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"345 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-310\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"750 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-311\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"400 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-312\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"926 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-313\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"408 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-314\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"905 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-315\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"309 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-316\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"796 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-317\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"628 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-318\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"789 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-319\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"264 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-320\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"613 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-321\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"584 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-322\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"682 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-323\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"192 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-324\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"871 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-325\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"340 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-326\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"980 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-327\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"304 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-328\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"904 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-329\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"413 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-330\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"136 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-331\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"654 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-332\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"552 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-333\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"640 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-334\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"736 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-335\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"673 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-336\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"389 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-337\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"449 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-338\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"473 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-339\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"108 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-340\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"466 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-341\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"878 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-342\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"115 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-343\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"223 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-344\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"890 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-345\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"690 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-346\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"694 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-347\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"113 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-348\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"439 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-349\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"733 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-350\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"693 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-351\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"460 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-352\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"817 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-353\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"884 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-354\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"526 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-355\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"364 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-356\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"542 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-357\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"793 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-358\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"828 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-359\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"544 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-360\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"851 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-361\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"938 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-362\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"474 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-363\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"661 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-364\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"654 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-365\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"102 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-366\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"978 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-367\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"116 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-368\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"907 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-369\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"629 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-370\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"223 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-371\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"134 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-372\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"449 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-373\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"918 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-374\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"393 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-375\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"581 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-376\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"173 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-377\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"481 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-378\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"584 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-379\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"536 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-380\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"947 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-381\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"908 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-382\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"291 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-383\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"360 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-384\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"780 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-385\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"354 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-386\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"857 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-387\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"907 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-388\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"450 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-389\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"721 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-390\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"763 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-391\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"193 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-392\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"573 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-393\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"638 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-394\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"494 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-395\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"117 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-396\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"226 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-397\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"337 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-398\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"468 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-399\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"203 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-400\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"664 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-401\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"336 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-402\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"799 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-403\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"593 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-404\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"107 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-405\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"490 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-406\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"938 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-407\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"918 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-408\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"253 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-409\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"563 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-410\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"834 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-411\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"108 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-412\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"944 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-413\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"677 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-414\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"426 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-415\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"674 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-416\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"588 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-417\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"339 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-418\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"544 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-419\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"410 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-420\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"984 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-421\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"446 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-422\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"424 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-423\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"749 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-424\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"815 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-425\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"531 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-426\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"834 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-427\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"813 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-428\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"506 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-429\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"920 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-430\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"390 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-431\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"997 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-432\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"624 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-433\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"367 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-434\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"632 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-435\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"602 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-436\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"823 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-437\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"345 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-438\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"558 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-439\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"540 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-440\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"992 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-441\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"724 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-442\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"431 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-443\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"204 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-444\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"188 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-445\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"434 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-446\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"324 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-447\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"513 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-448\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"469 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-449\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"685 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-450\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"929 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-451\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"496 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-452\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"171 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-453\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"664 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-454\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"313 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-455\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"182 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-456\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"882 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-457\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"379 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-458\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"656 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-459\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"409 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-460\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"473 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-461\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"382 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-462\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"417 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-463\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"915 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-464\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"285 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-465\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"969 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-466\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"582 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-467\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"552 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-468\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"802 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-469\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"891 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-470\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"158 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-471\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"578 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-472\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"849 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-473\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"951 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-474\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"469 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-475\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"738 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-476\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"396 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-477\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"430 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-478\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"872 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-479\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"960 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-480\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"288 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-481\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"953 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-482\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"505 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-483\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"456 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-484\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"350 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-485\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"148 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-486\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"397 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-487\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"206 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-488\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"860 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-489\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"936 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-490\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"951 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-491\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"271 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-492\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"296 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-493\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"842 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-494\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"254 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-495\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"186 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-496\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"214 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-497\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"665 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-498\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"140 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-499\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"648 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-500\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"759 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-501\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"203 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-502\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"299 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-503\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"695 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-504\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"358 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-505\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"425 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-506\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"716 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-507\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"167 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-508\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"473 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-509\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"565 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-510\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"165 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-511\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"134 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-512\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"808 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-513\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"560 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-514\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"931 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-515\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"782 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-516\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"854 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-517\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"658 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-518\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"903 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-519\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"419 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-520\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"759 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-521\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"765 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-522\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"896 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-523\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"162 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-524\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"731 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-525\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"267 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-526\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"317 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-527\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"439 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-528\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"974 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-529\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"966 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-530\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"762 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-531\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"740 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-532\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"800 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-533\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"391 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-534\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"594 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-535\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"751 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-536\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"400 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-537\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"781 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-538\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"253 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-539\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"708 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-540\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"290 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-541\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"702 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-542\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"310 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-543\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"492 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-544\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"534 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-545\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"462 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-546\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"583 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-547\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"542 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-548\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"234 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-549\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"733 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-550\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"457 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-551\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"771 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-552\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"800 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-553\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"810 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-554\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"218 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-555\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"258 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-556\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"766 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-557\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"608 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-558\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"339 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-559\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"878 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-560\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"426 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-561\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"316 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-562\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"963 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-563\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"137 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-564\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"136 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-565\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"880 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-566\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"683 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-567\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"256 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-568\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"177 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-569\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"509 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-570\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"892 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-571\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"521 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-572\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"683 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-573\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"227 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-574\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"644 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-575\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"859 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-576\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"106 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-577\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"503 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-578\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"888 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-579\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"705 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-580\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"553 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-581\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"336 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-582\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"869 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-583\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"895 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-584\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"346 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-585\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"763 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-586\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"587 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-587\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"689 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-588\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"176 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-589\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"125 KB\",\n    \"File type\": \"PDF\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-590\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"579 KB\",\n    \"File type\": \"PNG\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-591\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"942 KB\",\n    \"File type\": \"PPTX\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-592\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"593 KB\",\n    \"File type\": \"SVG\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"D4-593\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"578 KB\",\n    \"File type\": \"TXT\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"E5-594\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"135 KB\",\n    \"File type\": \"ZIP\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"F6-595\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"873 KB\",\n    \"File type\": \"BMP\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"G7-596\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"838 KB\",\n    \"File type\": \"CSV\",\n    \"Status\": \"Approved\",\n    \"Region\": \"North America\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"A1-597\",\n    \"Added by\": \"R. Jones\",\n    \"File size\": \"993 KB\",\n    \"File type\": \"DOCX\",\n    \"Status\": \"On hold\",\n    \"Region\": \"Asia Pacific\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"B2-598\",\n    \"Added by\": \"A. Miller\",\n    \"File size\": \"261 KB\",\n    \"File type\": \"GIF\",\n    \"Status\": \"Declined\",\n    \"Region\": \"Europe\",\n    \"Actions\": \"\"\n  },\n  {\n    \"File name\": \"C3-599\",\n    \"Added by\": \"S. Taylor\",\n    \"File size\": \"615 KB\",\n    \"File type\": \"JPG\",\n    \"Status\": \"In progress\",\n    \"Region\": \"South America\",\n    \"Actions\": \"\"\n  }\n]\n"
          },
          "name": "Dynamic table data"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/dynamic-table.constants.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/dynamic-table.constants.tsx": "import { VisaErrorTiny, VisaInformationTiny, VisaSuccessTiny, VisaWarningTiny } from '@visa/nova-icons-react';\nimport type { BadgeProperties } from '@visa/nova-react';\n\n/**\n * Row data to store string values for each column.\n * ie. { 'Status': 'Approved', 'Amount': '$1000', ... }\n */\nexport type RowData = Record<string, string>;\n\n/**\n * Row data for multi-action tables, where values can be string or an array of action buttons.\n */\nexport type RowDataMultiActions = Record<string, string | ActionButtons[]>;\n\n/**\n * Column data type definition.\n *\n * @property badge - (optional) Whether the column displays badge components\n * @property compact - (optional) Whether the column should use compact spacing\n * @property genericHeaderActions - (optional) Whether the column has generic header actions\n * @property headerActions - (optional) Settings for filter options\n * @property headerActions.options - Available filter options (FilterOption array or string array)\n * @property headerActions.selectedOptions - Currently selected filter values\n * @property hidden - (optional) Whether the column is currently hidden\n * @property identifier - (optional) Whether this column serves as the row identifier\n * @property name - Display name of the column\n * @property render - (optional) Custom function to render cell content\n * @property renderActionButtons - (optional) Custom function to render action buttons in cells\n * @property sortable - Whether the column supports sorting\n */\nexport type ColData = {\n  badge?: boolean;\n  compact?: boolean;\n  genericHeaderActions?: boolean;\n  headerActions?: {\n    options: FilterOption[] | string[];\n    selectedOptions: string[];\n  };\n  hidden?: boolean;\n  identifier?: boolean;\n  name: string;\n  render?: (rowData: RowData, colID?: string) => React.ReactNode;\n  renderActionButtons?: (rowData: RowDataMultiActions, colID?: string) => React.ReactNode;\n  sortable: boolean;\n};\n\n/**\n * Sort key type definition.\n *\n * @property column - Name of the column to sort by\n * @property direction - Sort direction (ascending, descending, or none)\n */\nexport type SortKeyType = {\n  column: string;\n  direction: SortType;\n};\n\n/**\n * Filterable table state type definition.\n *\n * @property column - Name of the column currently sorted\n * @property direction - Current sort direction (ascending, descending, or none)\n * @property filters - Currently applied filters grouped by column name\n *\n * Same as SortKeyType but with filters\n */\nexport type FilterableTableState = {\n  column: string;\n  direction: SortType;\n  filters: Record<string, string[]>;\n};\n\n/**\n * Sort type constants.\n */\nexport const SortType = {\n  NONE: 'none',\n  ASC: 'ascending',\n  DESC: 'descending',\n} as const;\nexport type SortType = (typeof SortType)[keyof typeof SortType];\n\n/**\n * Action buttons available in the dynamic table.\n */\nexport const ActionButtons = {\n  EDIT: 'edit',\n  DELETE: 'delete',\n} as const;\nexport type ActionButtons = (typeof ActionButtons)[keyof typeof ActionButtons];\n\n/**\n * Badge configurations for different statuses.\n *\n * @property type - Badge type from Nova (critical, neutral, stable, subtle, warning)\n * @property icon - Icon element to display in the badge\n * @property text - Display text for the badge status\n */\nexport const badgeConfigs: Array<{\n  type: BadgeProperties['badgeType'];\n  icon: React.ReactNode;\n  text: string;\n}> = [\n  {\n    type: 'critical',\n    icon: <VisaErrorTiny aria-label=\"error\" />,\n    text: 'Declined',\n  },\n  {\n    type: 'neutral',\n    icon: <VisaInformationTiny aria-label=\"information\" />,\n    text: 'In progress',\n  },\n  {\n    type: 'stable',\n    icon: <VisaSuccessTiny aria-label=\"success\" />,\n    text: 'Approved',\n  },\n  {\n    type: 'warning',\n    icon: <VisaWarningTiny aria-label=\"warning\" />,\n    text: 'On hold',\n  },\n];\n\n/**\n * Represents a single filter option with label and checked status.\n *\n * @property label - Display text for the filter option\n * @property checked - (optional) Whether the filter option is currently selected\n */\nexport type FilterOption = { label: string; checked?: boolean };\n\n/**\n * A group of filter options organized by filter name.\n */\nexport type FilterOptions = Record<string, FilterOption[]>;\n"
          },
          "name": "Dynamic table constants"
        },
        {
          "description": "",
          "order": 32,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/dynamic-table.scss"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/dynamic-table.scss": ".v-table {\n  thead {\n    .v-th {\n      // column header buttons should be extra small and less rounded\n      // this abides by the minimum size guidelines from WCAG for web\n      .v-button-icon {\n        --v-button-default-block-size: var(--size-scalable-26);\n        --v-button-default-border-radius: var(--size-rounded-small);\n      }\n    }\n  }\n\n  /** Apply to columns that should be as compact in width as possible */\n  .compact-column {\n    &.v-th {\n      /** This is a trick to make the column as small as possible.\n          Setting min-content or fit-content does not work. */\n      inline-size: 1%;\n    }\n\n    &.v-td {\n      inline-size: 1%;\n      --v-table-data-padding-inline: var(--size-scalable-6);\n    }\n\n    &.v-td {\n      /** Center content in compact columns */\n      text-align: center;\n    }\n  }\n\n  /** Allow button actions to be inline, even when in compact column */\n  .actions-wrapper {\n    display: inline-flex;\n    gap: 0.5rem;\n    inline-size: max-content;\n  }\n\n  &.fixed-table {\n    .sticky-row {\n      position: sticky;\n      top: 0;\n      z-index: 1;\n\n      // Drop shadow for sticky row\n      &::after {\n        content: '';\n        top: 0;\n        left: 0;\n        box-shadow: var(--elevation-large);\n        block-size: 100%;\n        inline-size: 100%;\n        position: absolute;\n        pointer-events: none; // allow clicks to pass through\n      }\n\n      .v-th,\n      .v-td {\n        // border-inline: 0 removes extra spacing caused by border-collapse: separate\n        border-inline: 0;\n        z-index: 2;\n      }\n    }\n\n    &:has(.sticky-row) {\n      // to keep the border between header and body when scrolling,\n      // border-collapse must be separate\n      --v-table-border-collapse: separate;\n    }\n\n    .pinned-column {\n      --v-table-header-bg-color: var(--palette-default-surface-3);\n      inset-inline-start: 0;\n      position: sticky;\n      z-index: 1;\n\n      /** Drop shadow for pinned column */\n      &::before {\n        content: '';\n        top: 0;\n        left: 0;\n        box-shadow: var(--elevation-medium);\n        block-size: 100%;\n        inline-size: 100%;\n        position: absolute;\n      }\n\n      &.v-td {\n        border: 0;\n      }\n    }\n\n    // maintain alternating row colors when pinned column is present\n    &.v-table-alt:has(.pinned-column) {\n      tr:nth-child(odd) td {\n        background-color: var(--v-table-background);\n      }\n      tr:nth-child(even) td {\n        background-color: var(--v-table-background-alt);\n      }\n    }\n\n    .v-th:has(.v-button.v-dropdown[aria-expanded='true']) {\n      // when a dropdown is open in the header, make sure it is above the shadow\n      z-index: 2;\n    }\n  }\n\n  &.accordion-style-table {\n    /**\n    * Override accordion display styles to work with table elements\n    * The directive names and class names don't always align,\n    * so we're using the directive selectors for clarity\n    **/\n    &.v-accordion {\n      display: table;\n    }\n\n    tbody {\n      display: table-row-group;\n\n      tr.v-accordion-heading {\n        display: table-row;\n        border: 0;\n\n        td {\n          // add a border to the start of each accordion header row\n          border-block-start: var(--v-accordion-panel-border-size) var(--v-accordion-panel-border-style)\n            var(--v-accordion-panel-border-color);\n        }\n\n        // for an open accordion item, add a border to bottom of row\n        &:has(.v-button[aria-expanded='true']) {\n          td {\n            border-block-end: var(--v-accordion-panel-border-size) var(--v-accordion-panel-border-style)\n              var(--v-accordion-panel-border-color);\n          }\n        }\n      }\n\n      &:first-of-type {\n        tr.v-accordion-heading td {\n          // remove border of first accordion header row\n          border-block-start: 0;\n        }\n      }\n    }\n\n    td.v-accordion-panel {\n      border: 0;\n    }\n  }\n\n  // selected row (row with checked checkbox)\n  tr:has(.row-selection-checkbox:checked) {\n    .v-td {\n      border-color: var(--palette-default-surface-lowlight);\n      background-color: var(--palette-default-surface-lowlight);\n      position: relative;\n\n      // blue highlight/indicator on inline-start of row\n      &:first-of-type {\n        &::before {\n          content: '';\n          /** push it up 1 border width, and make sure the height is 100% + 2 border widths (--size-scalable-1) */\n          block-size: calc(100% + 2 * var(--size-scalable-1));\n          inset-block-start: calc(-1 * var(--size-scalable-1));\n          position: absolute;\n          inset-block-start: 0;\n          inset-inline-start: 0;\n          border: 3px solid var(--palette-default-active);\n        }\n      }\n    }\n\n    &:last-of-type {\n      .v-td {\n        &:first-of-type {\n          &::before {\n            // On the last row, subtract 2px from the height to account for border radius.\n            // This prevents the extra height from causing a scrollbar to appear on the table.\n            block-size: calc(100% + (2 * var(--size-scalable-1)) - 2px);\n          }\n        }\n      }\n    }\n  }\n}\n\n.v-accordion-heading {\n  &.v-button {\n    /** Make badges position correctly inside header buttons instead of as a notification badge */\n    .v-badge-number {\n      position: relative;\n      justify-content: center;\n    }\n  }\n}\n\n.v-action-bar {\n  // remove rounded corners for action bars in dynamic table examples\n  --v-surface-border-radius: var(--size-rounded-none);\n\n  .v-dropdown-menu.v-surface {\n    /**\n    * Reset background for dropdown menus in action bars.\n    * Some action bars may have a different surface background color\n    * that the dropdowns would otherwise inherit.\n    */\n    --v-surface-background: var(--palette-default-surface-1);\n  }\n}\n"
          },
          "name": "Dynamic table styles"
        },
        {
          "description": "",
          "order": 33,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/dynamic-table.utils.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/dynamic-table.utils.tsx": "import type { BadgeProperties } from '@visa/nova-react';\nimport { badgeConfigs, SortType, type ColData, type RowData, type SortKeyType } from './dynamic-table.constants';\n\n/**\n * Sorts the data based on the given column and updates the sort state.\n *\n * @param sortKey - The key and direction to sort by\n * @param currentColumnData - Current column definitions\n * @param currentSortedData - Current data to be sorted\n * @returns Sorted data\n */\nexport const revisedSortTableData = (\n  sortKey: SortKeyType,\n  currentColumnData: ColData[] | ColData[],\n  currentSortedData: RowData[]\n): RowData[] => {\n  const columnName = sortKey.column;\n  // Create a copy of the column data to avoid mutating the original\n  const columnDataCopy = currentColumnData.map(col => ({ ...col }));\n\n  const columnToSort = columnDataCopy.find(c => c.name === columnName);\n  if (!columnToSort || !columnToSort.sortable) return currentSortedData;\n\n  // Create a copy of the data before sorting to avoid mutating the original array\n  const preSortedData = [...currentSortedData].sort((item1, item2) => {\n    const a = item1[columnName];\n    const b = item2[columnName];\n    if (columnToSort.badge) {\n      const aType = badgeConfigs.find(badge => badge.text === a)?.type;\n      const bType = badgeConfigs.find(badge => badge.text === b)?.type;\n      /** badge sorting */\n      return sortBadgeItems(aType, bType);\n    } else if (typeof a === 'string' && typeof b === 'string') {\n      /** string sorting */\n      return sortStringItems(a, b);\n    } else if (typeof a === 'boolean' && typeof b === 'boolean') {\n      /** boolean sorting */\n      return sortBoolItems(a, b);\n    }\n    return 0;\n  });\n\n  // return sorted data using new direction\n  if (sortKey.direction === SortType.ASC) {\n    return preSortedData;\n  } else {\n    const reversedData = [...preSortedData].reverse();\n    return reversedData;\n  }\n};\n\n/**\n * Sorts boolean items.\n *\n * @param a - First boolean value\n * @param b - Second boolean value\n * @returns Sorting order\n */\nexport const sortBoolItems = (a: boolean, b: boolean): number => {\n  if (a < b) {\n    return -1;\n  } else if (a > b) {\n    return 1;\n  }\n  return 0;\n};\n\n/**\n * Sorts string items.\n *\n * @param a - First string value\n * @param b - Second string value\n * @returns Sorting order\n */\nexport const sortStringItems = (a: string, b: string): number => {\n  // START GENAI@CHATGPT5\n  return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n  // END GENAI@CHATGPT5\n};\n\n/**\n * Sorts badge items by critical to least critical.\n *\n * @param a - Badge type of first item\n * @param b - Badge type of second item\n * @returns Sorting order\n */\nexport const sortBadgeItems = (a: BadgeProperties['badgeType'], b: BadgeProperties['badgeType']): number => {\n  const badgeOrder: BadgeProperties['badgeType'][] = ['critical', 'warning', 'stable', 'neutral'];\n  const indexA = badgeOrder.indexOf(a);\n  const indexB = badgeOrder.indexOf(b);\n\n  if (indexA < indexB) {\n    return -1;\n  } else if (indexA > indexB) {\n    return 1;\n  }\n  return 0;\n};\n"
          },
          "name": "Dynamic table utils"
        },
        {
          "description": "",
          "order": 34,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/filter-checkbox-groups.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/filter-checkbox-groups.tsx": "import React, { useState } from 'react';\nimport {\n  Utility,\n  Checkbox,\n  Label,\n  Listbox,\n  ListboxContainer,\n  ListboxItem,\n  UtilityFragment,\n  ScreenReader,\n  Button,\n} from '@visa/nova-react';\nimport type { ColData, FilterOption } from './dynamic-table.constants';\nimport { kebabCase } from 'change-case';\n\n/**\n * Props for FilterCheckboxGroups.\n *\n * @property column - Column information including available filter options\n * @property legend - (optional) Legend text for the fieldset, typically the column name\n * @property closeDropdown - (optional) Function to close the dropdown menu after an action\n * @property applyColumnFilters - (optional) Function that applies the selected filters\n * @property clearColumnFilters - (optional) Function that removes all filters\n */\ntype FilterCheckboxGroupsProps = {\n  column: ColData;\n  legend?: string;\n  closeDropdown?: () => void;\n  applyColumnFilters?: (column: ColData) => void;\n  clearColumnFilters?: (column: ColData) => void;\n};\n\n/**\n * Multi-select checkbox interface for filtering table columns. It automatically switches\n * between a simple list (for <5 options) and a scrollable listbox (for 5+ options) to\n * optimize for different data sets. Includes Apply and Clear all actions for batch filter\n * management.\n */\nconst FilterCheckboxGroups: React.FC<FilterCheckboxGroupsProps> = ({\n  column,\n  legend,\n  closeDropdown,\n  applyColumnFilters,\n  clearColumnFilters,\n}) => {\n  const [options, setOptions] = useState<FilterOption[]>(() => {\n    const opts = column.headerActions?.options as FilterOption[] | string[] | undefined;\n    if (!opts) return [];\n    return opts.map(option => {\n      if (typeof option === 'string') {\n        return { label: option, value: option };\n      }\n      return option;\n    });\n  });\n  const id = `filter-checkbox-group-${column.name.replace(/\\s+/g, '-').toLowerCase()}`;\n\n  /**\n   * Updates checkbox state and selected options when a filter option is toggled.\n   *\n   * @param option - The filter option being changed\n   * @param index - Index of the option in the options array\n   */\n  const handleCheckboxChange = (option: FilterOption, index: number) => {\n    const updatedOptions = [...options];\n    const checked = updatedOptions[index].checked || false;\n    updatedOptions[index].checked = !checked;\n\n    // Update the options state\n    setOptions(updatedOptions);\n\n    // Update the selected options array\n    let selectedOptions = column?.headerActions?.selectedOptions || [];\n    if (selectedOptions.includes(option.label)) {\n      selectedOptions = selectedOptions.filter(item => item !== option.label);\n    } else {\n      selectedOptions.push(option.label);\n    }\n    // Update the selected options in the column's headerActions\n    if (column.headerActions) {\n      column.headerActions.selectedOptions = selectedOptions;\n    }\n  };\n\n  return (\n    <>\n      {options.length < 5 ? (\n        <fieldset aria-labelledby={legend ? `${id}-legend` : undefined}>\n          {legend ? (\n            <UtilityFragment vMarginLeft={8} vPaddingTop={10}>\n              <Label id={`${id}-legend`} tag=\"legend\">\n                Filter by {column.name}\n              </Label>\n            </UtilityFragment>\n          ) : (\n            <ScreenReader tag=\"legend\">Filter by {column.name}</ScreenReader>\n          )}\n          <Utility tag=\"ul\" vFlex vFlexCol key={id} vMarginLeft={6}>\n            {options.map((option, index) => {\n              const value = kebabCase(option.label);\n              return (\n                <Utility key={value} tag=\"li\" vAlignItems=\"center\" vFlex vGap={2}>\n                  <Checkbox\n                    checked={option.checked || false}\n                    id={`${id}-option-${value}`}\n                    onChange={() => handleCheckboxChange(option, index)}\n                    value={value}\n                  />\n                  <Label htmlFor={`${id}-option-${value}`}>{option.label}</Label>\n                </Utility>\n              );\n            })}\n          </Utility>\n          {closeDropdown && applyColumnFilters && clearColumnFilters && (\n            <Utility vFlex vJustifyContent=\"between\" vPadding={6} vMarginTop={4}>\n              <Button\n                onClick={() => {\n                  closeDropdown();\n                  applyColumnFilters(column);\n                }}\n              >\n                Apply\n              </Button>\n              <Button\n                colorScheme=\"tertiary\"\n                onClick={() => {\n                  closeDropdown();\n                  clearColumnFilters(column);\n                }}\n              >\n                Clear all\n              </Button>\n            </Utility>\n          )}\n        </fieldset>\n      ) : (\n        <fieldset>\n          {legend ? (\n            <UtilityFragment vMarginLeft={8} vPaddingTop={10}>\n              <Label id={`${id}-legend`} tag=\"legend\">\n                Filter by {column.name}\n              </Label>\n            </UtilityFragment>\n          ) : (\n            <ScreenReader tag=\"legend\">Filter by {column.name}</ScreenReader>\n          )}\n          <UtilityFragment vMarginHorizontal={6}>\n            <ListboxContainer>\n              <Listbox id={id} scroll tag=\"div\">\n                {options.map((option, index) => (\n                  <ListboxItem<'label'> htmlFor={`${id}-option-${index}`} key={`${id}-option-${index}`} tag=\"label\">\n                    <Checkbox\n                      className=\"v-flex-shrink-0\"\n                      id={`${id}-option-${index}`}\n                      name={`${id}-option-${index}`}\n                      onChange={() => handleCheckboxChange(option, index)}\n                    />\n                    <Label tag=\"span\">{option.label}</Label>\n                  </ListboxItem>\n                ))}\n              </Listbox>\n            </ListboxContainer>\n          </UtilityFragment>\n          {closeDropdown && applyColumnFilters && clearColumnFilters && (\n            <Utility vFlex vJustifyContent=\"between\" vPadding={6} vMarginTop={4}>\n              <Button\n                onClick={() => {\n                  closeDropdown();\n                  applyColumnFilters(column);\n                }}\n              >\n                Apply\n              </Button>\n              <Button\n                colorScheme=\"tertiary\"\n                onClick={() => {\n                  closeDropdown();\n                  clearColumnFilters(column);\n                }}\n              >\n                Clear all\n              </Button>\n            </Utility>\n          )}\n        </fieldset>\n      )}\n    </>\n  );\n};\n\nexport default FilterCheckboxGroups;\n"
          },
          "name": "Filter checkbox groups"
        },
        {
          "description": "",
          "order": 35,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/filters.utils.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/filters.utils.tsx": "import {\n  badgeConfigs,\n  type ColData,\n  type FilterableTableState,\n  type FilterOption,\n  type RowData,\n  SortType,\n} from './dynamic-table.constants';\nimport { filterOptions } from './generate-demo-data.utils';\n\n/**\n * Generates seeded random numbers using the Mulberry32 algorithm.\n * Using a seed ensures the same sequence of numbers is generated each time.\n *\n * @param seed - Seed value for consistent random numbers\n * @returns Function that returns a random number between 0 and 1\n */\nexport const pseudoRandomGenerator = (seed: number) => {\n  return function () {\n    let t = (seed += 0x6d2b79f5);\n    t = Math.imul(t ^ (t >>> 15), t | 1);\n    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n};\n\n/**\n * Generates row data for the dynamic table based on the provided filter options.\n *\n * @param numRows - Number of rows to generate\n * @returns Generated row data\n */\nexport const generateFilterData = (numRows: number): RowData[] => {\n  const rows: RowData[] = [];\n  const fileNames = ['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8', 'I9', 'J10'];\n  // Use a seeded pseudo-random generator for deterministic results\n  const seed = 42;\n\n  for (let i = 0; i < numRows; i++) {\n    const rand = pseudoRandomGenerator(seed + i);\n\n    rows.push({\n      'File name': fileNames[i % fileNames.length] + '-' + (i + 100),\n      'Added by': filterOptions.addedBy[i % filterOptions.addedBy.length].label,\n      'File size': `${Math.floor(rand() * 900) + 100} KB`,\n      'File type': filterOptions.fileTypes[i % filterOptions.fileTypes.length].label,\n      Status: badgeConfigs[Math.floor(rand() * badgeConfigs.length)].text ?? 'approved',\n      Region: filterOptions.region[i % filterOptions.region.length].label,\n      Actions: '',\n    });\n  }\n  return rows;\n};\n\n/**\n * Filters the provided rows based on the applied filters.\n *\n * @param filters - Current applied filters\n * @param rows - Current row data\n * @returns Filtered row data\n */\nexport const getFilteredData = (filters: Record<string, string[]>, rows: RowData[]): RowData[] => {\n  let updatedRows: RowData[] = [...rows];\n  Object.keys(filters).forEach(columnName => {\n    const selectedOptions = filters[columnName];\n    if (selectedOptions.length > 0) {\n      if (columnName === 'File size') {\n        // Special handling for file size ranges\n        updatedRows = updatedRows.filter(row => {\n          const fileSizeStr = row['File size'];\n          const fileSizeNum = parseFloat(fileSizeStr.replace(' KB', ''));\n          const returnVar = selectedOptions.some(option => {\n            if (option === '< 300 KB') return fileSizeNum < 300;\n            if (option === '300-600 KB') return fileSizeNum >= 300 && fileSizeNum <= 600;\n            if (option === '> 600 KB') return fileSizeNum > 600;\n            return false;\n          });\n          return returnVar;\n        });\n      } else {\n        updatedRows = updatedRows.filter(row => selectedOptions.includes(row[columnName]));\n      }\n    }\n  });\n  return updatedRows;\n};\n\n/**\n * Collects all selected filters from all columns and returns them.\n *\n * @param columnData - Column data containing filter selections\n * @returns Updated filters object\n */\nexport const applyAllFilters = (columnData: ColData[]): Record<string, string[]> => {\n  const updatedFilters: Record<string, string[]> = {};\n  columnData.forEach(column => {\n    if (column.headerActions) {\n      const selectedOptions = column.headerActions.selectedOptions;\n      updatedFilters[column.name] = selectedOptions;\n    }\n  });\n  return updatedFilters;\n};\n\n/**\n * Gets and returns the selected filters for a single column.\n *\n * @param column - Column data containing filter selections\n * @returns Updated filters object\n */\nexport const applySingleColumnFilter = (column: ColData): Record<string, string[]> => {\n  const updatedFilters: Record<string, string[]> = {};\n  if (column.headerActions) {\n    const selectedOptions = column.headerActions.selectedOptions;\n    updatedFilters[column.name] = selectedOptions;\n  }\n  return updatedFilters;\n};\n\n/**\n * Removes all filters by resetting column selections.\n *\n * @param columnData - Column data to reset\n * @returns Updated column data and filters\n */\nexport const clearMultipleFilters = (\n  columnData: ColData[]\n): {\n  updatedColumnData: ColData[];\n  updatedFilters: Record<string, string[]>;\n} => {\n  const resetColData = columnData.map(col => {\n    if (col.headerActions) {\n      (col.headerActions.options as FilterOption[]).forEach(option => {\n        // since option.checked is optional, verify it's there before unsetting\n        if (option.checked) option.checked = false;\n      });\n      col.headerActions.selectedOptions = [];\n    }\n    return col;\n  });\n  return {\n    updatedColumnData: resetColData,\n    updatedFilters: {},\n  };\n};\n\n/**\n * Removes a single filter from the column data.\n *\n * @param filter - Name of the filter to remove\n * @param columnData - Column data to update\n * @returns Updated column data and filters\n */\nexport const clearSingleFilter = (\n  filter: string,\n  columnData: ColData[]\n): {\n  updatedColumnData: ColData[];\n  updatedFilters: Record<string, string[]>;\n} => {\n  const updatedFilters: Record<string, string[]> = {};\n  const updatedColData = columnData.map(col => {\n    if (col.headerActions) {\n      // Remove the filter from selectedOptions\n      col.headerActions.selectedOptions = col.headerActions.selectedOptions.filter(opt => opt !== filter);\n      updatedFilters[col.name] = col.headerActions.selectedOptions;\n      // Uncheck the option if present\n      (col.headerActions.options as FilterOption[]).forEach(option => {\n        if (option.label === filter && option.checked) {\n          option.checked = false;\n        }\n      });\n    }\n    return col;\n  });\n  return {\n    updatedColumnData: updatedColData,\n    updatedFilters: updatedFilters,\n  };\n};\n\n/**\n * Resets column data to default state.\n *\n * @param columnData - Column data to reset\n * @returns Reset column data\n */\nexport const getResetColumnData = (columnData: ColData[]): ColData[] => {\n  return columnData.map(column => ({\n    ...column,\n    hidden: false,\n    sorted: SortType.NONE,\n    pinned: false,\n    headerActions: column.headerActions ? { ...column.headerActions, selectedOptions: [] } : column.headerActions,\n  }));\n};\n\n/**\n * Resets the table to its default state, including column visibility and filters.\n *\n * @param columnData - Current column data\n * @param setColumnData - Function to update column data\n * @param setTableState - Function to update table state\n * @param setFilterPopupOpen - Function to update filter popup open state (to close after reset)\n */\nexport const resetTable = (\n  columnData: ColData[],\n  setColumnData: React.Dispatch<React.SetStateAction<ColData[]>>,\n  setTableState: React.Dispatch<React.SetStateAction<FilterableTableState>>,\n  setFilterPopupOpen: React.Dispatch<React.SetStateAction<boolean>>\n) => {\n  // Reset hidden columns\n  const resetColData = getResetColumnData(columnData);\n  setColumnData(resetColData);\n  // Reset filters\n  setTableState({\n    column: '',\n    direction: SortType.NONE,\n    filters: {},\n  });\n  setFilterPopupOpen(false);\n};\n\n/**\n * Updates column visibility based on which columns should be hidden.\n *\n * @param columnData - Current column data\n * @param hiddenColumns - Array indicating which columns should be hidden\n * @param setColumnData - Function to update column data\n */\nexport const manageColumnVisibility = (\n  columnData: ColData[],\n  hiddenColumns: boolean[],\n  setColumnData: React.Dispatch<React.SetStateAction<ColData[]>>\n) => {\n  const updatedColData = [...columnData];\n  updatedColData.forEach((column, index) => {\n    column.hidden = hiddenColumns[index];\n  });\n  setColumnData(updatedColData);\n};\n\n/**\n * Shows or hides a column and updates the hidden columns array.\n *\n * @param column - Column to show or hide\n * @param hiddenColumns - Array indicating which columns are hidden\n * @param columnData - Current column data\n * @param setHiddenColumns - Function to update hidden columns\n * @param setColumnData - Optional function to update column data - if provided, applies change immediately\n */\nexport const handleColumnVisibilityChange = (\n  column: ColData,\n  hiddenColumns: boolean[],\n  columnData: ColData[],\n  setHiddenColumns: React.Dispatch<React.SetStateAction<boolean[]>>,\n  setColumnData?: React.Dispatch<React.SetStateAction<ColData[]>>\n) => {\n  const columnIndex = columnData.indexOf(column);\n  const updatedHiddenColumns = [...hiddenColumns];\n  updatedHiddenColumns[columnIndex] = !updatedHiddenColumns[columnIndex];\n  setHiddenColumns(updatedHiddenColumns);\n\n  // If setColumnData is provided, apply the change immediately to columnData\n  if (setColumnData) {\n    const updatedColData = [...columnData];\n    updatedColData[columnIndex] = { ...updatedColData[columnIndex], hidden: updatedHiddenColumns[columnIndex] };\n    setColumnData(updatedColData);\n  }\n};\n\n/**\n * Opens or closes a column filter dropdown.\n *\n * @param index - Index from columnData (not visibleColumnData)\n * @param columnFiltersOpen - Array indicating which column filter dropdowns are open\n * @param setColumnFiltersOpen - Function to update column filter dropdowns\n * @param isOpen - Optional boolean to set the open state explicitly; defaults to false\n */\nexport const toggleColumnDropdown = (\n  index: number,\n  columnFiltersOpen: boolean[],\n  setColumnFiltersOpen: React.Dispatch<React.SetStateAction<boolean[]>>,\n  isOpen = false\n) => {\n  const updatedOpenStates = [...columnFiltersOpen];\n  updatedOpenStates[index] = isOpen;\n  setColumnFiltersOpen(updatedOpenStates);\n};\n"
          },
          "name": "Filter utils"
        },
        {
          "description": "",
          "order": 36,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/generate-demo-data.utils.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/generate-demo-data.utils.tsx": "import ActionsButton from './actions-button';\nimport StatusBadge from './badge';\nimport { badgeConfigs, type ColData, type FilterOptions, type RowData } from './dynamic-table.constants';\n\n/** === DEFAULT DATA === */\n\n/**\n * Generates default column data for demo purposes.\n *\n * @param actions - Whether to include actions column\n * @returns Array of column definitions\n */\nexport const getDefaultColumnData = (actions = true): ColData[] => {\n  const data = [\n    { name: 'Column A', sortable: true, identifier: true },\n    { name: 'Column B', sortable: true },\n    ...(actions\n      ? [\n          {\n            name: 'Column C',\n            sortable: true,\n            badge: true,\n            render: (row: RowData) => <StatusBadge label={row['Column C']} />,\n          },\n          {\n            name: 'Actions',\n            sortable: false,\n            compact: true,\n            render: (row: RowData, colID?: string) => <ActionsButton label={row[colID || 'Column A']} />,\n          },\n        ]\n      : [\n          { name: 'Column C', sortable: true },\n          {\n            name: 'Column D',\n            sortable: true,\n            badge: true,\n            render: (row: RowData) => <StatusBadge label={row['Column D']} />,\n          },\n        ]),\n  ];\n  return data;\n};\n\n/**\n * Generates basic row data for demo purposes.\n *\n * @param numRows - Number of rows to generate\n * @param columnData - Array of column definitions to determine data types\n * @returns Array of row data objects with basic content\n */\nexport const generateBasicData = (numRows: number, columnData: ColData[]): RowData[] => {\n  const rows: RowData[] = [];\n  for (let i = 0; i < numRows; i++) {\n    const row: RowData = {};\n    columnData.forEach(col => {\n      if (col.badge) {\n        row[col.name] = badgeConfigs[i % badgeConfigs.length].text ?? 'Approved';\n      } else if (col.compact) {\n        row[col.name] = '';\n      } else {\n        /** Generate string data like A1, B1, C1, etc. */\n        row[col.name] = `${String.fromCharCode(65 + columnData.indexOf(col))}${i + 1}`;\n      }\n    });\n    rows.push(row);\n  }\n  return rows;\n};\n\n/** === DEMO FILTER DATA === */\n\n/**\n * Filter options for demo purposes.\n */\nexport const filterOptions: FilterOptions = {\n  addedBy: [{ label: 'A. Miller' }, { label: 'S. Taylor' }, { label: 'R. Jones' }],\n  region: [{ label: 'North America' }, { label: 'Asia Pacific' }, { label: 'Europe' }, { label: 'South America' }],\n  fileTypes: [\n    { label: 'BMP' },\n    { label: 'CSV' },\n    { label: 'DOCX' },\n    { label: 'GIF' },\n    { label: 'JPG' },\n    { label: 'PDF' },\n    { label: 'PNG' },\n    { label: 'PPTX' },\n    { label: 'SVG' },\n    { label: 'TXT' },\n    { label: 'ZIP' },\n  ],\n  fileSizes: [{ label: '< 300 KB' }, { label: '300-600 KB' }, { label: '> 600 KB' }],\n  badgeTypes: badgeConfigs.map(config => ({ label: config.text, value: config.text })),\n};\n\n/**\n * Column data with filter options for demo purposes.\n */\nexport const columnDataFilterDefaults: ColData[] = [\n  { name: 'File name', sortable: true, identifier: true },\n  {\n    name: 'Added by',\n    sortable: true,\n    headerActions: { options: filterOptions.addedBy, selectedOptions: [] },\n  },\n  {\n    name: 'File size',\n    sortable: true,\n    headerActions: { options: filterOptions.fileSizes, selectedOptions: [] },\n  },\n  {\n    name: 'File type',\n    sortable: true,\n    headerActions: { options: filterOptions.fileTypes, selectedOptions: [] },\n  },\n  {\n    name: 'Status',\n    sortable: true,\n\n    headerActions: {\n      options: badgeConfigs.map(config => ({ label: config.text, value: config.text })),\n      selectedOptions: [],\n    },\n    render: (row: RowData) => <StatusBadge label={row['Status']} />,\n  },\n  {\n    name: 'Region',\n    sortable: true,\n    headerActions: { options: filterOptions.region, selectedOptions: [] },\n  },\n  {\n    name: 'Actions',\n    compact: true,\n    sortable: false,\n    render: (row: RowData) => <ActionsButton label={row['File name']} />,\n  },\n];\n"
          },
          "name": "Generate demo data"
        },
        {
          "description": "",
          "order": 37,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/mock-table-api.utils.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/mock-table-api.utils.tsx": "import type { ColData, RowData, SortKeyType } from './dynamic-table.constants';\nimport { revisedSortTableData } from './dynamic-table.utils';\nimport dynamicTableData from './dynamic-table-data.json';\n\n/**\n * Response structure that simulates a real paginated API endpoint.\n *\n * @property data - Array of row data for the current page\n * @property total - Total number of items across all pages\n * @property page - Current page number (1-based)\n * @property pageSize - Number of items per page\n */\nexport interface PaginatedResponse {\n  data: RowData[];\n  total: number;\n  page: number;\n  pageSize: number;\n}\n\n/**\n * Simulates a paginated API endpoint with server-side sorting.\n *\n * @param page - The page number to fetch (1-based)\n * @param pageSize - Number of items per page\n * @param sortKey - Object containing column name and sort direction\n * @param columnData - Column definitions for proper sorting\n * @param delayMs - Optional delay in milliseconds to simulate network latency (default: 800ms)\n * @returns Promise of paginated response with data, total count, and metadata\n */\nexport const getTablePage = async (\n  page: number,\n  pageSize: number,\n  sortKey: SortKeyType,\n  columnData: ColData[],\n  delayMs: number = 800\n): Promise<PaginatedResponse> => {\n  // Simulate network delay\n  await new Promise(resolve => setTimeout(resolve, delayMs));\n\n  const fullData = dynamicTableData as RowData[];\n\n  // Simulate server-side sorting\n  // In a real API, this would be handled by the database (ORDER BY clause)\n  const sortedData = revisedSortTableData(sortKey, columnData, fullData);\n\n  // Simulate server-side pagination\n  // In a real API, this would be handled by LIMIT/OFFSET or similar\n  const start = (page - 1) * pageSize;\n  const end = start + pageSize;\n\n  // Return API-like response structure\n  return {\n    data: sortedData.slice(start, end),\n    total: fullData.length,\n    page,\n    pageSize,\n  };\n};\n\n/**\n * Simulates fetching accordion panel data for a specific row.\n *\n * @param rowId - The identifier of the row to fetch details for\n * @param delayMs - Optional delay in milliseconds to simulate network latency (default: 800ms)\n * @returns Promise of accordion data for the specified row\n */\nexport const getAccordionData = async (rowId: string, delayMs: number = 800): Promise<RowData> => {\n  // Simulate network delay\n  await new Promise(resolve => setTimeout(resolve, delayMs));\n\n  const fullData = dynamicTableData as RowData[];\n\n  // Find the specific row by its File name (identifier)\n  const rowData = fullData.find(row => row['File name'] === rowId);\n\n  if (!rowData) {\n    throw new Error(`Row with ID ${rowId} not found`);\n  }\n\n  // In a real application, the server would return additional details\n  // For this demo, we return the full row data which includes all fields\n  return rowData;\n};\n"
          },
          "name": "Mock table API"
        },
        {
          "description": "",
          "order": 38,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/pagination-shared.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/pagination-shared.tsx": "import { useRef, type CSSProperties, type FormEvent } from 'react';\nimport {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronDownTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Button,\n  InputContainer,\n  InputControl,\n  InputMessage,\n  Label,\n  Pagination,\n  PaginationOverflow,\n  Select,\n  Utility,\n  UtilityFragment,\n  calculatePagesFromTo,\n  usePagination,\n} from '@visa/nova-react';\n\n/**\n * Props for DynamicTablePagination.\n *\n * @property className - (optional) Class name for styling\n * @property disabled - (optional) Whether the pagination is disabled\n * @property onItemsPerPageChange - Function called when changing how many items show per page\n * @property page - Current page number\n * @property pageSize - Current page size\n * @property pageSizeOptions - (optional) Options for page size selection\n * @property showItemsPerPage - (optional) Whether to show the items-per-page selector\n * @property totalCount - Total number of items\n * @property id - Unique identifier for the pagination component\n */\nexport type DynamicTablePaginationProps = {\n  className?: string;\n  disabled?: boolean;\n  onItemsPerPageChange: (number: number) => void;\n  page: number;\n  pageSize: number;\n  pageSizeOptions?: number[];\n  showItemsPerPage?: boolean;\n  totalCount: number;\n  id: string;\n} & Omit<ReturnType<typeof usePagination>, 'selectedPage'>;\n\n/**\n * Reusable pagination component that provides page navigation controls and a results-per-page\n * selector. It shows which items you're viewing out of the total, and provides buttons for\n * moving between pages. Works with Nova's usePagination hook to manage the current page.\n */\nconst DynamicTablePagination = ({\n  isFirstPage,\n  isLastPage,\n  onFirstPage,\n  onItemsPerPageChange,\n  onLastPage,\n  onNextPage,\n  onPageChange,\n  onPreviousPage,\n  page,\n  pages,\n  pageSize = 10,\n  pageSizeOptions = [10, 20, 50],\n  showItemsPerPage = true,\n  totalCount,\n  id,\n}: DynamicTablePaginationProps) => {\n  const firstPageRef = useRef<HTMLButtonElement>(null);\n  const lastPageRef = useRef<HTMLButtonElement>(null);\n  const { from, to } = calculatePagesFromTo(totalCount, pageSize, page);\n\n  // Determines if pagination controls should be displayed\n  // True when there is more than one page of data\n  const canPaginate = pages.length > 1;\n\n  // Hide the entire component if there's only one page and items-per-page selector is disabled\n  if (!canPaginate && !showItemsPerPage) return <></>;\n\n  /**\n   * Changes the items per page and returns to the first page.\n   *\n   * @param event - Select element change event\n   */\n  const handleItemsPerPageChange = (event: FormEvent<HTMLSelectElement>) => {\n    onFirstPage();\n    onItemsPerPageChange(+event.currentTarget.value);\n  };\n\n  /**\n   * Navigates to the first page and focuses the first page button.\n   */\n  const handleFirstPage = () => {\n    onFirstPage();\n    firstPageRef.current?.focus();\n  };\n\n  /**\n   * Navigates to the last page and focuses the last page button.\n   */\n  const handleLastPage = () => {\n    onLastPage();\n    lastPageRef.current?.focus();\n  };\n\n  return (\n    <Utility vAlignItems=\"center\" vFlex vFlexRow vFlexWrapReverse vGap={10} vJustifyContent=\"between\">\n      <Utility\n        style={{ textWrap: 'nowrap' } as CSSProperties}\n        tag=\"fieldset\"\n        vAlignItems=\"center\"\n        vFlex\n        vFlexRow\n        vGap={12}\n      >\n        <UtilityFragment vFlexShrink0>\n          <Label htmlFor={`${id}-select-items-per-page`}>Results per page</Label>\n        </UtilityFragment>\n        <InputContainer>\n          <Select\n            id={`${id}-select-items-per-page`}\n            name={`${id}-select-items-per-page`}\n            onChange={handleItemsPerPageChange}\n            value={pageSize}\n          >\n            {pageSizeOptions.map(option => (\n              <option key={option} value={option}>\n                {option}\n              </option>\n            ))}\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n        <InputMessage id={`select-message-${id}`}>Showing {`${from} - ${to} of ${totalCount}`}</InputMessage>\n      </Utility>\n      <UtilityFragment>\n        <nav aria-label={`table pagination ${id}`} role=\"navigation\">\n          <UtilityFragment vAlignItems=\"center\" vFlex vFlexRow vGap={4}>\n            <Pagination>\n              <li>\n                <Button\n                  aria-label=\"Go to first page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isFirstPage}\n                  iconButton\n                  onClick={handleFirstPage}\n                >\n                  <VisaArrowStartTiny rtl />\n                </Button>\n              </li>\n              <li>\n                <Button\n                  aria-label=\"Go to previous page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isFirstPage}\n                  iconButton\n                  onClick={onPreviousPage}\n                >\n                  <VisaChevronLeftTiny rtl />\n                </Button>\n              </li>\n              {pages.map((pageNumber, index) =>\n                pageNumber === -1 ? (\n                  <UtilityFragment key={`${id}-pagination-ellipse-${index}`} vAlignItems=\"center\" vFlex>\n                    <PaginationOverflow>\n                      <VisaOptionHorizontalTiny />\n                    </PaginationOverflow>\n                  </UtilityFragment>\n                ) : (\n                  <li key={`${id}-pagination-page-${pageNumber}`}>\n                    <Button\n                      aria-current={page === pageNumber}\n                      aria-label={`Page ${pageNumber}`}\n                      colorScheme=\"tertiary\"\n                      onClick={() => onPageChange(pageNumber as number)}\n                      ref={index === 0 ? firstPageRef : index === pages.length - 1 ? lastPageRef : undefined}\n                    >\n                      {pageNumber}\n                    </Button>\n                  </li>\n                )\n              )}\n              <li>\n                <Button\n                  aria-label=\"Go to next page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isLastPage}\n                  iconButton\n                  onClick={onNextPage}\n                >\n                  <VisaChevronRightTiny rtl />\n                </Button>\n              </li>\n              <li>\n                <Button\n                  aria-label=\"Go to last page\"\n                  buttonSize=\"small\"\n                  colorScheme=\"tertiary\"\n                  disabled={isLastPage}\n                  iconButton\n                  onClick={handleLastPage}\n                >\n                  <VisaArrowEndTiny rtl />\n                </Button>\n              </li>\n            </Pagination>\n          </UtilityFragment>\n        </nav>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n\nexport default DynamicTablePagination;\n"
          },
          "name": "Pagination"
        },
        {
          "description": "",
          "order": 39,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/sort-icon.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/sort-icon.tsx": "import { VisaSortableTiny, VisaSortAscendingTiny, VisaSortDescendingTiny } from '@visa/nova-icons-react';\nimport { SortType } from './dynamic-table.constants';\n\n/**\n * Props for SortIcon.\n *\n * @property sorted - Current sort state determining which icon to display\n */\ninterface SortIconProps {\n  sorted: SortType | undefined;\n}\n\n/**\n * Displays the appropriate sort indicator icon based on the current sort state of a column.\n * It cycles between unsorted, ascending, and descending states, providing clear visual\n * feedback about the current sort direction.\n */\nconst SortIcon = ({ sorted }: SortIconProps) => {\n  return sorted === SortType.ASC ? (\n    <VisaSortAscendingTiny />\n  ) : sorted === SortType.DESC ? (\n    <VisaSortDescendingTiny />\n  ) : (\n    <VisaSortableTiny />\n  );\n};\n\nexport default SortIcon;\n"
          },
          "name": "Sort icon"
        },
        {
          "description": "",
          "order": 40,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/dynamic-table/table-dropdown-button.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/dynamic-table/shared/table-dropdown-button.tsx": "import type { CSSProperties } from 'react';\nimport {\n  autoUpdate,\n  flip,\n  FloatingFocusManager,\n  offset,\n  shift,\n  useClick,\n  useDismiss,\n  useFloating,\n  useInteractions,\n} from '@floating-ui/react';\nimport { DropdownButton, DropdownMenu, UtilityFragment } from '@visa/nova-react';\n\n/**\n * Props for TableDropdownButton.\n *\n * @property id - Unique identifier for the dropdown button and menu elements\n * @property open - Whether the dropdown menu is currently open\n * @property setOpen - Function to open or close the dropdown\n * @property icon - Icon to display within the dropdown button\n * @property buttonAriaLabel - Accessible label for the button\n * @property children - (optional) Dropdown menu content to display when open\n */\ninterface TableDropdownButtonProps {\n  id: string;\n  open: boolean;\n  setOpen: (open: boolean) => void;\n  icon: React.ReactNode;\n  buttonAriaLabel: string;\n  children?: React.ReactNode;\n}\n\n/**\n * Dropdown button that uses Floating UI for positioning and accessibility. It makes sure menus\n * open in the right place and manages keyboard focus for accessibility. Used throughout the\n * table examples for action menus, filters, and settings.\n */\nconst TableDropdownButton = ({ id, open, setOpen, icon, buttonAriaLabel, children }: TableDropdownButtonProps) => {\n  // useFloating determines where the dropdown menu appears on screen\n  // It calculates the menu's position and provides references to connect the button and menu\n  const {\n    context: context,\n    floatingStyles: floatingStyles,\n    refs: ref,\n  } = useFloating({\n    middleware: [offset(2), flip(), shift()], // Place menu 2px below button, flip to other side if no space, adjust position to stay visible\n    open: open,\n    placement: 'bottom-end', // Align dropdown to bottom-right of trigger button\n    onOpenChange: setOpen,\n    whileElementsMounted: autoUpdate, // Keep menu position up-to-date while open\n  });\n  // useClick allows opening and closing the menu when clicked\n  const clickRef = useClick(context);\n  // useDismiss allows closing the menu when clicking outside or pressing Escape\n  const dismissMenu = useDismiss(context);\n  // useInteractions combines the click and dismiss behaviors and provides properties to connect everything\n  const { getReferenceProps, getFloatingProps } = useInteractions([clickRef, dismissMenu]);\n\n  return (\n    <>\n      <UtilityFragment vMarginLeft={'auto'}>\n        <DropdownButton\n          aria-expanded={open}\n          aria-controls={open ? `${id}-label-dropdown-menu` : undefined}\n          aria-label={buttonAriaLabel}\n          buttonSize=\"small\"\n          colorScheme=\"tertiary\"\n          ref={ref.setReference}\n          iconButton\n          {...getReferenceProps()}\n        >\n          {icon}\n        </DropdownButton>\n      </UtilityFragment>\n      {open && (\n        <FloatingFocusManager context={context} modal={false} restoreFocus={true} initialFocus={-1}>\n          <DropdownMenu\n            id={`${id}-label-dropdown-menu`}\n            aria-hidden={!open}\n            style={\n              {\n                inlineSize: '180px',\n                '--v-surface-background': 'var(--palette-default-surface-1)', // prevent inheriting from action bar's surface 2 background\n                position: 'absolute',\n                ...floatingStyles,\n                zIndex: 3,\n              } as CSSProperties\n            }\n            ref={ref.setFloating}\n            {...getFloatingProps()}\n          >\n            {children}\n          </DropdownMenu>\n        </FloatingFocusManager>\n      )}\n    </>\n  );\n};\n\nexport default TableDropdownButton;\n"
          },
          "name": "Table dropdown button"
        }
      ],
      "propertySections": [],
      "properties": []
    },
    {
      "name": "file-upload",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "patterns",
      "exampleSections": [
        {
          "name": "Automatic file upload",
          "description": "",
          "order": 1
        },
        {
          "name": "Manual file upload",
          "description": "",
          "order": 2
        },
        {
          "name": "Shared Components",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Automatic file upload",
          "url": {
            "iframe": "patterns/file-upload/multi-file-upload",
            "github": "apps/workshop/src/examples/patterns/file-upload/multi-file-upload.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/file-upload/multi-file-upload.tsx": "import {\n  Button,\n  Flag,\n  FlagCloseButton,\n  FlagContent,\n  ScreenReader,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport {\n  MessageIcon,\n  VisaDocumentPdfLow,\n  VisaDeleteTiny,\n  VisaDocumentLow,\n  VisaDocumentPngLow,\n  VisaDocumentJpgLow,\n  VisaCloseTiny,\n} from '@visa/nova-icons-react';\nimport type { UploadFile } from './shared/types';\nimport { UploadCard } from './shared/upload-card';\nimport { FileStatusButton } from './shared/file-status-button';\nimport { mockUpload } from './shared/mock-upload';\n\nimport { useRef, useState } from 'react';\n\n// File size limit - customize as needed\nexport const MAX_FILE_SIZE = 25 * 1024 * 1024; // 25MB\n\n// Accepted file types with corresponding icons - add/remove types as needed\nexport const ACCEPTED_FILE_TYPES = [\n  { type: 'application/pdf', icon: <VisaDocumentPdfLow /> },\n  { type: 'image/png', icon: <VisaDocumentPngLow /> },\n  { type: 'image/jpeg', icon: <VisaDocumentJpgLow /> },\n];\n\n/**\n * Validates and prepares a file for upload.\n * Assigns appropriate icon based on file type and creates a unique ID for tracking.\n *\n * @param f - Native File object from browser\n * @returns UploadFile object with icon, unique ID, and file reference\n */\nconst validateFile = (f: File): UploadFile => {\n  let icon = undefined;\n  const acceptedTypeObj = ACCEPTED_FILE_TYPES.find(t => t.type === f.type);\n  if (!acceptedTypeObj) {\n    icon = <VisaDocumentLow />;\n  } else {\n    icon = acceptedTypeObj.icon;\n  }\n\n  return {\n    file: f,\n    // Create unique ID combining sanitized filename and size for duplicate detection\n    id: `${f.name.replace(/[^a-zA-Z0-9-_]/g, '-')}-${f.size}`,\n    icon,\n  };\n};\n\n/**\n * Multiple file upload with drag-and-drop support and concurrent automatic uploads.\n * Includes duplicate detection, batch retry functionality, and clickable error file links for keyboard navigation.\n */\nconst MultiFileUpload = () => {\n  // Hidden file input reference for programmatic triggering\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  // Refs for managing focus on retry buttons of failed files\n  const retryRefs = useRef<Record<string, (element: HTMLDivElement | null) => void>>({});\n  const retryElements = useRef<Record<string, HTMLDivElement | null>>({});\n\n  // Array of all files being tracked (uploading, uploaded, or failed)\n  const [uploadedFiles, setUploadedFiles] = useState<UploadFile[]>([]);\n\n  // Controls visibility of error section message\n  const [showSectionMessage, setShowSectionMessage] = useState(true);\n\n  // Controls visibility of success flag notification\n  const [showFlag, setShowFlag] = useState(true);\n\n  // Tracks drag state for visual feedback\n  const [isDragging, setIsDragging] = useState(false);\n\n  /**\n   * Processes selected or dropped files.\n   * Validates files, filters duplicates, and initiates upload for each.\n   * Important: All uploads start concurrently.\n   *\n   * @param files - FileList from input or drop event\n   */\n  const processFiles = (files: FileList) => {\n    const filesArray = Array.from(files);\n\n    const validatedFiles: UploadFile[] = filesArray.map(f => {\n      return validateFile(f);\n    });\n\n    setUploadedFiles((prevValidatedFiles: UploadFile[]) => {\n      const newlyValidatedFiles = validatedFiles\n        // Filter out duplicates based on ID to prevent re-uploading same file\n        .filter(file => !prevValidatedFiles.some(f => f.id === file.id))\n        .map(f => ({\n          ...f,\n          uploading: true,\n        }));\n\n      newlyValidatedFiles.forEach(newFileItem => {\n        // Replace mockUpload with your actual upload API call\n        mockUpload(newFileItem, {\n          maxFileSize: MAX_FILE_SIZE,\n          acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n        })\n          .then(() => {\n            setUploadedFiles(current =>\n              current.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: true, error: undefined } : f\n              )\n            );\n            setShowFlag(true);\n          })\n          .catch((err: Error) => {\n            setUploadedFiles(current =>\n              current.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: false, error: err.message } : f\n              )\n            );\n            setShowSectionMessage(true);\n          });\n      });\n\n      return [...prevValidatedFiles, ...newlyValidatedFiles];\n    });\n  };\n\n  /**\n   * Triggers the hidden file input when Select button is clicked.\n   */\n  const handleSelectFilesClick = () => {\n    if (fileInputRef.current) {\n      fileInputRef.current.click();\n    }\n  };\n\n  /**\n   * Handles file input change and processes selected files.\n   *\n   * @param event - Change event from file input\n   */\n  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const files = event.target.files;\n    if (files && files.length > 0) {\n      processFiles(files);\n    }\n  };\n\n  /**\n   * Removes a file from the uploaded files list.\n   * Hides success flag if deleting an errored file.\n   *\n   * @param fileToDelete - File to remove from tracking\n   */\n  const handleDeleteFile = (fileToDelete: UploadFile) => {\n    setUploadedFiles(files => files.filter(file => file.id !== fileToDelete.id));\n    if (fileToDelete.error) {\n      setShowFlag(false);\n    }\n  };\n\n  /**\n   * Retries all failed file uploads.\n   */\n  const handleRetryAll = () => {\n    erroredFiles.forEach(f => handleRetryFile(f));\n  };\n\n  /**\n   * Retries upload for a single failed file.\n   *\n   * @param fileToRetry - File with error state to retry\n   */\n  const handleRetryFile = (fileToRetry: UploadFile) => {\n    const validatedFile = validateFile(fileToRetry.file);\n\n    setUploadedFiles(files => files.map(f => (f.id === fileToRetry.id ? { ...validatedFile, uploading: true } : f)));\n    setShowSectionMessage(true);\n\n    mockUpload(fileToRetry, {\n      maxFileSize: MAX_FILE_SIZE,\n      acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n    })\n      .then(() => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? { ...f, uploading: false, uploaded: true, error: undefined }\n              : f\n          )\n        );\n\n        setShowFlag(true);\n      })\n      .catch(err => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? {\n                  ...f,\n                  uploading: false,\n                  uploaded: false,\n                  error: err?.message || 'Error: Failed to upload file to server.',\n                }\n              : f\n          )\n        );\n\n        setShowSectionMessage(true);\n      });\n  };\n\n  /**\n   * Hides the error section message.\n   */\n  const handleSectionMessageClose = () => {\n    setShowSectionMessage(false);\n  };\n\n  /**\n   * Hides the success flag notification.\n   */\n  const handleFlagClose = () => {\n    setShowFlag(false);\n  };\n\n  /**\n   * Handles file drop events.\n   * Processes dropped files immediately.\n   *\n   * @param event - Drag event containing dropped files\n   */\n  const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {\n    event.preventDefault();\n    const files = event.dataTransfer.files;\n    if (files && files.length > 0) {\n      processFiles(files);\n    }\n    setIsDragging(false);\n  };\n\n  /**\n   * Handles drag over events to prevent default behavior and show visual feedback.\n   *\n   * @param event - Drag event during drag over\n   */\n  const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {\n    event.preventDefault();\n    setIsDragging(true);\n  };\n\n  /**\n   * Handles drag leave events to remove visual feedback.\n   *\n   * @param event - Drag event when leaving drop zone\n   */\n  const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {\n    event.preventDefault();\n    setIsDragging(false);\n  };\n\n  // Computed values for UI state\n  const erroredFiles = uploadedFiles.filter(f => !!f.error);\n  const uploadingFiles = uploadedFiles.filter(f => !!f.uploading);\n  const allFilesUploaded =\n    uploadedFiles.length > 0 && uploadedFiles.filter(f => f.uploaded).length === uploadedFiles.length;\n\n  // Create callback refs for retry buttons to enable keyboard navigation to errors\n  erroredFiles.forEach(f => {\n    if (!retryRefs.current[f.id]) {\n      retryRefs.current[f.id] = (element: HTMLDivElement | null) => {\n        retryElements.current[f.id] = element;\n      };\n    }\n  });\n\n  return (\n    <Utility vFlex vFlexCol vGap={25}>\n      <Utility vFlex vFlexCol vGap={4} style={{ maxWidth: '400px' }}>\n        <Utility vFlex vFlexCol vGap={16}>\n          <Utility vFlex vFlexCol vGap={8}>\n            <Typography tag=\"h4\" variant=\"subtitle-1\">\n              Upload files\n            </Typography>\n            {/* Update instructions to match your MAX_FILE_SIZE and ACCEPTED_FILE_TYPES */}\n            <Typography variant=\"label-small\">\n              Choose one or more files to upload, up to 25 MB each. Accepted file types are .pdf, .png, and .jpg.\n            </Typography>\n          </Utility>\n          {/* Drag-and-drop zone with visual feedback when dragging */}\n          <Utility\n            vFlex\n            vFlexCol\n            vJustifyContent=\"center\"\n            vAlignItems=\"center\"\n            vGap={8}\n            style={{\n              border: '1px solid var(--palette-default-active)',\n              borderRadius: 'var(--theme-border-radius)',\n              height: '158px',\n              background: isDragging ? 'var(--palette-default-surface-highlight)' : 'initial',\n            }}\n            onDrop={handleDrop}\n            onDragOver={handleDragOver}\n            onDragLeave={handleDragLeave}\n          >\n            {/* Hidden file input with multiple file support */}\n            <ScreenReader<'input'>\n              tag=\"input\"\n              type=\"file\"\n              multiple\n              ref={fileInputRef}\n              onChange={handleFileChange}\n              hidden\n            ></ScreenReader>\n            <Typography>Drag and drop files or</Typography>\n            <Button colorScheme=\"secondary\" onClick={handleSelectFilesClick}>\n              Select file(s)\n            </Button>\n          </Utility>\n        </Utility>\n        {/* Always-present live region */}\n        <Utility vFlex vFlexCol vGap={8} role=\"status\" style={{ minHeight: '1rem' }}>\n          {!!uploadingFiles.length && (\n            <Typography variant=\"label-small\">{`Uploading ${uploadingFiles.length} file${uploadingFiles.length > 1 ? 's' : ''}...`}</Typography>\n          )}\n          {/* Error message with clickable file links for keyboard navigation to retry buttons */}\n          {!!erroredFiles.length && !uploadingFiles.length && showSectionMessage && (\n            <UtilityFragment vMarginVertical={21}>\n              <SectionMessage messageType=\"error\">\n                <MessageIcon messageType=\"error\" />\n                <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                  <SectionMessageContent style={{ wordBreak: 'break-all' }}>\n                    <Typography>The following files have errors:</Typography>\n                    <UtilityFragment vPaddingLeft={20}>\n                      <ul style={{ listStyle: 'initial' }}>\n                        {erroredFiles.map(f => (\n                          <li key={f.file.name + f.file.size}>\n                            <Typography<'a'>\n                              tag=\"a\"\n                              href=\"#\"\n                              onClick={e => {\n                                e.preventDefault();\n                                retryElements.current[f.id]?.focus();\n                              }}\n                            >\n                              {f.file.name}\n                            </Typography>\n                          </li>\n                        ))}\n                      </ul>\n                    </UtilityFragment>\n                    {erroredFiles.length > 1 && (\n                      <UtilityFragment vMarginTop={8}>\n                        <Button colorScheme=\"secondary\" onClick={handleRetryAll}>\n                          Retry all\n                        </Button>\n                      </UtilityFragment>\n                    )}\n                  </SectionMessageContent>\n                </UtilityFragment>\n                <SectionMessageCloseButton onClick={handleSectionMessageClose}>\n                  <VisaCloseTiny />\n                </SectionMessageCloseButton>\n              </SectionMessage>\n            </UtilityFragment>\n          )}\n        </Utility>\n        {/* Display all tracked files with status and actions */}\n        {!!uploadedFiles.length && (\n          <Utility tag=\"ul\" vFlex vFlexCol vGap={8} aria-label=\"Uploaded files\">\n            {uploadedFiles.map(uploadFile => (\n              <UploadCard\n                key={uploadFile.id}\n                file={uploadFile}\n                renderActions={() => (\n                  <>\n                    <FileStatusButton\n                      ref={retryRefs.current[uploadFile.id]}\n                      uploadFile={uploadFile}\n                      onRetry={() => handleRetryFile(uploadFile)}\n                    />\n                    <Button\n                      aria-label={`Delete ${uploadFile.file.name}`}\n                      colorScheme=\"tertiary\"\n                      iconButton\n                      onClick={() => handleDeleteFile(uploadFile)}\n                    >\n                      <VisaDeleteTiny />\n                    </Button>\n                  </>\n                )}\n              />\n            ))}\n          </Utility>\n        )}\n      </Utility>\n      {/* Success notification - positioned at bottom right */}\n      <Utility role=\"alert\" vAlignSelf=\"end\">\n        {showFlag && allFilesUploaded && (\n          <Flag messageType=\"success\">\n            <MessageIcon messageType=\"success\" />\n            <FlagContent className=\"v-pl-2 v-pb-2\">Files uploaded successfully.</FlagContent>\n            <FlagCloseButton onClick={handleFlagClose}>\n              <VisaCloseTiny />\n            </FlagCloseButton>\n          </Flag>\n        )}\n      </Utility>\n    </Utility>\n  );\n};\n\nexport default MultiFileUpload;\n"
          },
          "name": "Multi-file upload"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Automatic file upload",
          "url": {
            "iframe": "patterns/file-upload/single-file-upload",
            "github": "apps/workshop/src/examples/patterns/file-upload/single-file-upload.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/file-upload/single-file-upload.tsx": "import {\n  Button,\n  Flag,\n  FlagCloseButton,\n  FlagContent,\n  ScreenReader,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport {\n  MessageIcon,\n  VisaDocumentPdfLow,\n  VisaDeleteTiny,\n  VisaDocumentLow,\n  VisaDocumentPngLow,\n  VisaDocumentJpgLow,\n  VisaCloseTiny,\n} from '@visa/nova-icons-react';\nimport type { UploadFile } from './shared/types';\nimport { UploadCard } from './shared/upload-card';\nimport { FileStatusButton } from './shared/file-status-button';\nimport { mockUpload } from './shared/mock-upload';\n\nimport { useRef, useState } from 'react';\n\n// File size limit - customize as needed\nexport const MAX_FILE_SIZE = 25 * 1024 * 1024; // 25MB\n\n// Accepted file types with corresponding icons - add/remove types as needed\nexport const ACCEPTED_FILE_TYPES = [\n  { type: 'application/pdf', icon: <VisaDocumentPdfLow /> },\n  { type: 'image/png', icon: <VisaDocumentPngLow /> },\n  { type: 'image/jpeg', icon: <VisaDocumentJpgLow /> },\n];\n\n/**\n * Validates and prepares a file for upload.\n * Assigns appropriate icon based on file type and creates a unique ID for tracking.\n *\n * @param f - Native File object from browser\n * @returns UploadFile object with icon, unique ID, and file reference\n */\nconst validateFile = (f: File): UploadFile => {\n  let icon = undefined;\n  const acceptedTypeObj = ACCEPTED_FILE_TYPES.find(t => t.type === f.type);\n  if (!acceptedTypeObj) {\n    icon = <VisaDocumentLow />;\n  } else {\n    icon = acceptedTypeObj.icon;\n  }\n\n  return {\n    file: f,\n    // Create unique ID combining sanitized filename and size for duplicate detection\n    id: `${f.name.replace(/[^a-zA-Z0-9-_]/g, '-')}-${f.size}`,\n    icon,\n  };\n};\n\n/**\n * Single file upload with automatic upload on selection and inline progress display.\n * Includes error handling with retry functionality and success notification via Flag.\n */\nconst SingleFileUpload = () => {\n  // Hidden file input reference for programmatic triggering\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  // Current file being uploaded/displayed\n  const [uploadedFile, setUploadedFile] = useState<UploadFile | undefined>();\n\n  // Controls visibility of error section message\n  const [showSectionMessage, setShowSectionMessage] = useState(true);\n\n  // Controls visibility of success flag notification\n  const [showFlag, setShowFlag] = useState(true);\n\n  /**\n   * Triggers the hidden file input when Select button is clicked.\n   */\n  const handleSelectFilesClick = () => {\n    if (fileInputRef.current) {\n      fileInputRef.current.click();\n    }\n  };\n\n  /**\n   * Handles file selection and initiates automatic upload.\n   * Validates file, sets uploading state, and calls upload API.\n   * Important: Upload starts immediately upon file selection.\n   *\n   * @param event - Change event from file input containing selected file\n   */\n  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const files = event.target.files;\n    if (files && files.length > 0) {\n      const file = files[0];\n\n      const uploadFile = validateFile(file);\n\n      setUploadedFile({ ...uploadFile, uploading: true });\n\n      // Replace mockUpload with your actual upload API call\n      mockUpload(uploadFile, {\n        maxFileSize: MAX_FILE_SIZE,\n        acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n      })\n        .then(() => {\n          setUploadedFile(previousFile => {\n            // Ensure file wasn't deleted during upload\n            if (!previousFile) {\n              return undefined;\n            }\n            // Ensure we're updating the correct file (prevents race conditions)\n            if (previousFile.id !== uploadFile.id) {\n              return previousFile;\n            }\n            return {\n              ...uploadFile,\n              uploading: false,\n              uploaded: true,\n              error: undefined,\n            };\n          });\n          setShowSectionMessage(true);\n        })\n        .catch((err: Error) => {\n          setUploadedFile(previousFile => {\n            // Ensure file wasn't deleted during upload\n            if (!previousFile) {\n              return undefined;\n            }\n            // Ensure we're updating the correct file (prevents race conditions)\n            if (previousFile.id !== uploadFile.id) {\n              return previousFile;\n            }\n            return {\n              ...uploadFile,\n              uploading: false,\n              uploaded: false,\n              error: err.message,\n            };\n          });\n          setShowSectionMessage(true);\n        });\n    }\n  };\n\n  /**\n   * Removes the uploaded file from display.\n   * Hides success flag if deleting an errored file.\n   *\n   * @param fileToDelete - File to remove from the uploaded file list\n   */\n  const handleDeleteFile = (fileToDelete: UploadFile) => {\n    setUploadedFile(undefined);\n\n    if (fileToDelete.error) {\n      setShowFlag(false);\n    }\n  };\n\n  /**\n   * Retries upload for a failed file.\n   * Re-validates file and attempts upload again.\n   *\n   * @param fileToRetry - File with error state to retry uploading\n   */\n  const handleRetryFile = (fileToRetry: UploadFile) => {\n    const validatedFile = validateFile(fileToRetry.file);\n\n    setUploadedFile({ ...validatedFile, uploading: true });\n    setShowSectionMessage(true);\n\n    mockUpload(fileToRetry, {\n      maxFileSize: MAX_FILE_SIZE,\n      acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n    })\n      .then(() => {\n        setUploadedFile(previousFile => {\n          // Ensure file wasn't deleted during retry\n          if (!previousFile) {\n            return undefined;\n          }\n          // Ensure we're updating the correct file (prevents race conditions)\n          if (previousFile.id !== fileToRetry.id) {\n            return previousFile;\n          }\n          return {\n            ...fileToRetry,\n            uploading: false,\n            uploaded: true,\n            error: undefined,\n          };\n        });\n        setShowFlag(true);\n      })\n      .catch((err: Error) => {\n        setUploadedFile(previousFile => {\n          // Ensure file wasn't deleted during retry\n          if (!previousFile) {\n            return undefined;\n          }\n          // Ensure we're updating the correct file (prevents race conditions)\n          if (previousFile.id !== fileToRetry.id) {\n            return previousFile;\n          }\n          return {\n            ...fileToRetry,\n            uploading: false,\n            uploaded: false,\n            error: err.message,\n          };\n        });\n        setShowFlag(true);\n      });\n  };\n\n  /**\n   * Hides the error section message.\n   */\n  const handleSectionMessageClose = () => {\n    setShowSectionMessage(false);\n  };\n\n  /**\n   * Hides the success flag notification.\n   */\n  const handleFlagClose = () => {\n    setShowFlag(false);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap={25}>\n      <Utility vFlex vFlexCol vGap={4} style={{ maxWidth: '400px' }}>\n        <Utility vFlex vFlexCol vGap={16}>\n          <Utility vFlex vFlexCol vGap={8}>\n            <Typography tag=\"h4\" variant=\"subtitle-1\">\n              Upload file\n            </Typography>\n            {/* Update instructions to match your MAX_FILE_SIZE and ACCEPTED_FILE_TYPES */}\n            <Typography variant=\"label-small\">\n              Choose one file to upload, up to 25 MB each. Accepted file types are .pdf, .png, and .jpg.\n            </Typography>\n          </Utility>\n          <>\n            {/* Hidden file input - triggered programmatically by Select button */}\n            <ScreenReader<'input'>\n              tag={'input'}\n              type=\"file\"\n              hidden\n              ref={fileInputRef}\n              onChange={handleFileChange}\n            ></ScreenReader>\n            <UtilityFragment vAlignSelf=\"start\">\n              <Button colorScheme=\"secondary\" onClick={handleSelectFilesClick}>\n                Select file\n              </Button>\n            </UtilityFragment>\n          </>\n        </Utility>\n        {/* Always-present live region */}\n        <div role=\"status\" style={{ minHeight: '1rem' }}>\n          {uploadedFile?.uploading && <Typography variant=\"label-small\">Upload in progress...</Typography>}\n          {uploadedFile?.error && showSectionMessage && (\n            <UtilityFragment vMarginVertical={21}>\n              <SectionMessage messageType=\"error\">\n                <MessageIcon messageType=\"error\" />\n                <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                  <SectionMessageContent style={{ wordBreak: 'break-all' }}>\n                    <Typography>File failed to upload.</Typography>\n                  </SectionMessageContent>\n                </UtilityFragment>\n                <SectionMessageCloseButton onClick={handleSectionMessageClose}>\n                  <VisaCloseTiny />\n                </SectionMessageCloseButton>\n              </SectionMessage>\n            </UtilityFragment>\n          )}\n        </div>\n        {/* Display uploaded file with status and actions */}\n        {!!uploadedFile && (\n          <Utility tag=\"ul\">\n            <UploadCard\n              file={uploadedFile}\n              renderActions={() => (\n                <>\n                  <FileStatusButton uploadFile={uploadedFile} onRetry={() => handleRetryFile(uploadedFile)} />\n                  <Button\n                    aria-label={`Delete ${uploadedFile.file.name}`}\n                    colorScheme=\"tertiary\"\n                    iconButton\n                    onClick={() => handleDeleteFile(uploadedFile)}\n                  >\n                    <VisaDeleteTiny />\n                  </Button>\n                </>\n              )}\n            />\n          </Utility>\n        )}\n      </Utility>\n      {/* Success notification - positioned at bottom right */}\n      <Utility role=\"alert\" vAlignSelf=\"end\">\n        {showFlag && uploadedFile && uploadedFile.uploaded && (\n          <Flag messageType=\"success\">\n            <MessageIcon messageType=\"success\" />\n            <FlagContent className=\"v-pl-2 v-pb-2\">File uploaded successfully.</FlagContent>\n            <FlagCloseButton onClick={handleFlagClose}>\n              <VisaCloseTiny />\n            </FlagCloseButton>\n          </Flag>\n        )}\n      </Utility>\n    </Utility>\n  );\n};\n\nexport default SingleFileUpload;\n"
          },
          "name": "Single-file upload"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Manual file upload",
          "url": {
            "iframe": "patterns/file-upload/multi-file-manual-upload",
            "github": "apps/workshop/src/examples/patterns/file-upload/multi-file-manual-upload.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/file-upload/multi-file-manual-upload.tsx": "import {\n  Button,\n  Flag,\n  FlagCloseButton,\n  FlagContent,\n  ScreenReader,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n} from '@visa/nova-react';\nimport {\n  MessageIcon,\n  VisaDocumentPdfLow,\n  VisaDeleteTiny,\n  VisaDocumentLow,\n  VisaDocumentJpgLow,\n  VisaCloseTiny,\n  VisaDocumentXlsLow,\n} from '@visa/nova-icons-react';\n\nimport { UploadCard } from './shared/upload-card';\nimport { UploadDialog } from './shared/upload-dialog';\nimport type { UploadFile } from './shared/types';\nimport { mockUpload } from './shared/mock-upload';\n\nimport { useRef, useState } from 'react';\nimport { FileStatusButton } from './shared/file-status-button';\n\n// File size limit - customize as needed\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB\n\n// Accepted file types with corresponding icons - add/remove types as needed\nexport const ACCEPTED_FILE_TYPES = [\n  { type: 'image/jpeg', icon: <VisaDocumentJpgLow /> },\n  { type: 'application/pdf', icon: <VisaDocumentPdfLow /> },\n  { type: 'application/msword', icon: <VisaDocumentLow /> },\n  { type: 'application/vnd.ms-excel', icon: <VisaDocumentXlsLow /> },\n];\n\n/**\n * Validates and prepares a file for upload.\n * Assigns appropriate icon based on file type and creates a unique ID for tracking.\n *\n * @param f - Native File object from browser\n * @returns UploadFile object with icon, unique ID, and file reference\n */\nconst validateFile = (f: File): UploadFile => {\n  let icon = undefined;\n\n  const acceptedTypeObj = ACCEPTED_FILE_TYPES.find(t => t.type === f.type);\n  if (!acceptedTypeObj) {\n    icon = <VisaDocumentLow />;\n  } else {\n    icon = acceptedTypeObj.icon;\n  }\n\n  return {\n    file: f,\n    // Create unique ID combining sanitized filename and size for duplicate detection\n    id: `${f.name.replace(/[^a-zA-Z0-9-_]/g, '-')}-${f.size}`,\n    icon,\n  };\n};\n\n// Dialog configuration - customize as needed\nconst uploadQueueDialogId = 'manual-upload-dialog';\nconst UPLOAD_DIALOG_TITLE = 'Upload files';\nconst UPLOAD_DIALOG_DESCRIPTION =\n  'Upload one or more files, up to 10 MB each. Accepted file types are .jpg, .pdf, .docx, and .xlsx. Only files that meet these requirements will be uploaded.';\n\n/**\n * Multiple file upload with Dialog-based review before manual upload trigger.\n * Files are queued for review in a Dialog and only uploaded when user confirms, allowing file removal before upload.\n */\nconst MultiFileManualUpload = () => {\n  // Hidden file input reference for programmatic triggering\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  // Refs for managing focus on retry buttons of failed files\n  const retryRefs = useRef<Record<string, (element: HTMLDivElement | null) => void>>({});\n  const retryElements = useRef<Record<string, HTMLDivElement | null>>({});\n\n  // Files that have been uploaded or are uploading\n  const [uploadedFiles, setUploadedFiles] = useState<UploadFile[]>([]);\n\n  // Files awaiting user confirmation in dialog (not yet uploading)\n  const [queuedFiles, setQueuedFiles] = useState<UploadFile[]>([]);\n\n  // Controls visibility of error section message\n  const [showSectionMessage, setShowSectionMessage] = useState(true);\n\n  // Controls visibility of success flag notification\n  const [showFlag, setShowFlag] = useState(true);\n\n  /**\n   * Triggers the hidden file input when Select button is clicked.\n   */\n  const handleSelectFilesClick = () => {\n    if (fileInputRef.current) {\n      fileInputRef.current.click();\n    }\n  };\n\n  /**\n   * Handles file selection and adds files to queue.\n   * Important: Files are NOT uploaded immediately - they are queued in dialog.\n   *\n   * @param event - Change event from file input\n   */\n  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const files = event.target.files;\n    if (files && files.length > 0) {\n      const filesArray = Array.from(files);\n\n      const uploadFiles: UploadFile[] = filesArray.map(f => validateFile(f));\n\n      setQueuedFiles((prevQueuedFiles: UploadFile[]) => {\n        const newlyQueuedFiles = uploadFiles\n          // Filter out duplicates based on ID to prevent adding same file twice\n          .filter(file => !prevQueuedFiles.some(f => f.id === file.id));\n\n        return [...prevQueuedFiles, ...newlyQueuedFiles];\n      });\n    }\n  };\n\n  /**\n   * Handles upload button click in dialog.\n   * Closes dialog and initiates concurrent uploads for all queued files.\n   */\n  const handleUploadClick = () => {\n    handleCloseDialog();\n\n    setUploadedFiles((oldUploadFiles: UploadFile[]) => {\n      const newUploadFiles = queuedFiles\n        // Filter out files already tracked to prevent re-uploading\n        .filter(file => !oldUploadFiles.some(f => f.id === file.id))\n        .map(f => ({\n          ...f,\n          uploading: true,\n        }));\n\n      newUploadFiles.forEach(newFileItem => {\n        // Replace mockUpload with your actual upload API call\n        mockUpload(newFileItem, {\n          maxFileSize: MAX_FILE_SIZE,\n          acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n        })\n          .then(() => {\n            setUploadedFiles(oldUploadFiles =>\n              oldUploadFiles.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: true, error: undefined } : f\n              )\n            );\n            setShowFlag(true);\n          })\n          .catch((err: Error) => {\n            setUploadedFiles(oldUploadFiles =>\n              oldUploadFiles.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: false, error: err.message } : f\n              )\n            );\n            setShowSectionMessage(true);\n          });\n      });\n\n      return [...oldUploadFiles, ...newUploadFiles];\n    });\n  };\n\n  /**\n   * Removes a file from the uploaded files list.\n   * Hides success flag if deleting an errored file.\n   *\n   * @param fileToDelete - File to remove from tracking\n   */\n  const handleDeleteFile = (fileToDelete: UploadFile) => {\n    setUploadedFiles(files => files.filter(file => file.id !== fileToDelete.id));\n    if (fileToDelete.error) {\n      setShowFlag(false);\n    }\n  };\n\n  /**\n   * Removes a file from the queue (before upload).\n   *\n   * @param fileToDelete - File to remove from queue\n   */\n  const handleDeleteQueuedFile = (fileToDelete: UploadFile) => {\n    setQueuedFiles(files => files.filter(file => file.id !== fileToDelete.id));\n  };\n\n  /**\n   * Retries all failed file uploads.\n   */\n  const handleRetryAll = () => {\n    erroredFiles.forEach(f => handleRetryFile(f));\n  };\n\n  /**\n   * Retries upload for a single failed file.\n   *\n   * @param fileToRetry - File with error state to retry\n   */\n  const handleRetryFile = (fileToRetry: UploadFile) => {\n    const validatedFile = validateFile(fileToRetry.file);\n\n    // Update file state to uploading and clear previous error\n    setUploadedFiles(files => files.map(f => (f.id === fileToRetry.id ? { ...validatedFile, uploading: true } : f)));\n    setShowSectionMessage(true);\n\n    mockUpload(fileToRetry, {\n      maxFileSize: MAX_FILE_SIZE,\n      acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n    })\n      .then(() => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? { ...f, uploading: false, uploaded: true, error: undefined }\n              : f\n          )\n        );\n\n        setShowFlag(true);\n      })\n      .catch(err => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? {\n                  ...f,\n                  uploading: false,\n                  uploaded: false,\n                  error: err?.message || 'Error: Failed to upload file to server.',\n                }\n              : f\n          )\n        );\n\n        setShowSectionMessage(true);\n      });\n  };\n\n  // Computed values for UI state\n  const erroredFiles = uploadedFiles.filter(f => !!f.error);\n  const uploadingFiles = uploadedFiles.filter(f => !!f.uploading);\n\n  const allFilesUploaded =\n    uploadedFiles.length > 0 && uploadedFiles.filter(f => f.uploaded).length === uploadedFiles.length;\n\n  // Create callback refs for retry buttons to enable keyboard navigation to errors\n  erroredFiles.forEach(f => {\n    if (!retryRefs.current[f.id]) {\n      retryRefs.current[f.id] = (element: HTMLDivElement | null) => {\n        retryElements.current[f.id] = element;\n      };\n    }\n  });\n\n  /**\n   * Hides the error section message.\n   */\n  const handleSectionMessageClose = () => {\n    setShowSectionMessage(false);\n  };\n\n  /**\n   * Hides the success flag notification.\n   */\n  const handleFlagClose = () => {\n    setShowFlag(false);\n  };\n\n  /**\n   * Handles dialog close - clears queued files.\n   */\n  const handleCloseDialog = () => {\n    setQueuedFiles([]);\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap={25}>\n      <Utility vFlex vFlexCol vGap={4} style={{ maxWidth: '400px' }}>\n        <Utility vFlex vFlexCol vGap={16}>\n          <Utility vFlex vFlexCol vGap={8}>\n            <Typography tag=\"h4\" variant=\"subtitle-1\">\n              Upload files\n            </Typography>\n            {/* Update instructions to match your MAX_FILE_SIZE and ACCEPTED_FILE_TYPES */}\n            <Typography variant=\"label-small\">\n              Choose one or more files to upload, up to 10MB each. Accepted file types are jpg, pdf, docx, and xlsx.\n            </Typography>\n          </Utility>\n          {/* Hidden file input with multiple file support */}\n          <ScreenReader<'input'>\n            tag={'input'}\n            type=\"file\"\n            hidden\n            multiple\n            ref={fileInputRef}\n            onChange={handleFileChange}\n          ></ScreenReader>\n          <UtilityFragment vAlignSelf=\"start\">\n            <Button colorScheme=\"secondary\" onClick={handleSelectFilesClick}>\n              Select file(s)\n            </Button>\n          </UtilityFragment>\n        </Utility>\n        {/* Always-present live region */}\n        <Utility vFlex vFlexCol vGap={8} role=\"status\" style={{ minHeight: '1rem' }}>\n          {!!uploadingFiles.length && (\n            <Typography variant=\"label-small\">{`Uploading ${uploadingFiles.length} file${uploadingFiles.length > 1 ? 's' : ''}...`}</Typography>\n          )}\n          {/* Error message with clickable file links for keyboard navigation to retry buttons */}\n          {!!erroredFiles.length && showSectionMessage && (\n            <UtilityFragment vMarginVertical={21}>\n              <SectionMessage messageType=\"error\">\n                <MessageIcon messageType=\"error\" />\n                <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                  <SectionMessageContent style={{ wordBreak: 'break-all' }}>\n                    <Typography>The following files have errors:</Typography>\n                    <UtilityFragment vPaddingLeft={20}>\n                      <ul style={{ listStyle: 'initial' }}>\n                        {erroredFiles.map(f => (\n                          <li key={f.file.name + f.file.size}>\n                            <Typography<'a'>\n                              tag=\"a\"\n                              href=\"#\"\n                              onClick={e => {\n                                e.preventDefault();\n                                retryElements.current[f.id]?.focus();\n                              }}\n                            >\n                              {f.file.name}\n                            </Typography>\n                          </li>\n                        ))}\n                      </ul>\n                    </UtilityFragment>\n                    {erroredFiles.length > 1 && (\n                      <UtilityFragment vMarginTop={8}>\n                        <Button colorScheme=\"secondary\" onClick={handleRetryAll}>\n                          Retry all\n                        </Button>\n                      </UtilityFragment>\n                    )}\n                  </SectionMessageContent>\n                </UtilityFragment>\n                <SectionMessageCloseButton onClick={handleSectionMessageClose}>\n                  <VisaCloseTiny />\n                </SectionMessageCloseButton>\n              </SectionMessage>\n            </UtilityFragment>\n          )}\n        </Utility>\n        {/* Display uploaded/uploading files with status and actions */}\n        {!!uploadedFiles.length && (\n          <Utility tag=\"ul\" vFlex vFlexCol vGap={8}>\n            {uploadedFiles.map(uploadFile => (\n              <UploadCard\n                key={uploadFile.id}\n                file={uploadFile}\n                renderActions={() => (\n                  <>\n                    <FileStatusButton\n                      ref={retryRefs.current[uploadFile.id]}\n                      uploadFile={uploadFile}\n                      onRetry={() => handleRetryFile(uploadFile)}\n                    />\n                    <Button\n                      aria-label={`Delete ${uploadFile.file.name}`}\n                      colorScheme=\"tertiary\"\n                      iconButton\n                      onClick={() => handleDeleteFile(uploadFile)}\n                    >\n                      <VisaDeleteTiny />\n                    </Button>\n                  </>\n                )}\n              />\n            ))}\n          </Utility>\n        )}\n      </Utility>\n      {/* Success notification - positioned at bottom right */}\n      <Utility role=\"alert\" vAlignSelf=\"end\">\n        {showFlag && allFilesUploaded && (\n          <Flag messageType=\"success\">\n            <MessageIcon messageType=\"success\" />\n            <FlagContent className=\"v-pl-2 v-pb-2\">Files uploaded successfully.</FlagContent>\n            <FlagCloseButton onClick={handleFlagClose}>\n              <VisaCloseTiny />\n            </FlagCloseButton>\n          </Flag>\n        )}\n      </Utility>\n      {/* Dialog shows when files are queued - opens automatically when queuedFiles has items */}\n      <UploadDialog\n        isOpen={queuedFiles.length > 0}\n        title={UPLOAD_DIALOG_TITLE}\n        description={UPLOAD_DIALOG_DESCRIPTION}\n        queuedFiles={queuedFiles}\n        onSelectFiles={handleSelectFilesClick}\n        onUpload={handleUploadClick}\n        onClose={handleCloseDialog}\n        onDeleteQueuedFile={handleDeleteQueuedFile}\n        dialogId={uploadQueueDialogId}\n      />\n    </Utility>\n  );\n};\n\nexport default MultiFileManualUpload;\n"
          },
          "name": "Multi-file manual upload"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Manual file upload",
          "url": {
            "iframe": "patterns/file-upload/file-upload-with-alternate-display",
            "github": "apps/workshop/src/examples/patterns/file-upload/file-upload-with-alternate-display.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/file-upload/file-upload-with-alternate-display.tsx": "import {\n  Button,\n  Flag,\n  FlagCloseButton,\n  FlagContent,\n  ScreenReader,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n  TableWrapper,\n  Table,\n  Thead,\n  Tr,\n  Th,\n  Tbody,\n} from '@visa/nova-react';\nimport {\n  MessageIcon,\n  VisaDocumentPdfLow,\n  VisaDocumentLow,\n  VisaDocumentPngLow,\n  VisaDocumentJpgLow,\n  VisaCloseTiny,\n  VisaSortableTiny,\n  VisaSortAscendingTiny,\n  VisaSortDescendingTiny,\n} from '@visa/nova-icons-react';\n\nimport { useMemo, useRef, useState, type CSSProperties } from 'react';\n\nimport { UploadRow } from './shared/upload-row';\nimport { UploadDialog } from './shared/upload-dialog';\nimport { SortType, type ColData, type SortKeyType, type UploadFile } from './shared/types';\nimport { mockUpload } from './shared/mock-upload';\n\n// File size limit - customize as needed\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB\n\n// Accepted file types with corresponding icons - add/remove types as needed\nexport const ACCEPTED_FILE_TYPES = [\n  { type: 'application/pdf', icon: <VisaDocumentPdfLow /> },\n  { type: 'image/png', icon: <VisaDocumentPngLow /> },\n  { type: 'image/jpeg', icon: <VisaDocumentJpgLow /> },\n];\n\n// Dialog configuration - customize as needed\nconst UPLOAD_DIALOG_TITLE = 'Upload Files';\nconst UPLOAD_DIALOG_DESCRIPTION =\n  'Upload one or more files, up to 10 MB each. Accepted file types are .jpg, .pdf, .docx, and .xlsx. Only files that meet these requirements will be uploaded.';\nconst uploadQueueDialogId = 'manual-file-upload-alternative-dialog';\n\n/**\n * Validates and prepares a file for upload.\n * Assigns appropriate icon based on file type and creates a unique ID for tracking.\n *\n * @param f - Native File object from browser\n * @returns UploadFile object with icon, unique ID, and file reference\n */\nconst validateFile = (f: File): UploadFile => {\n  let icon = undefined;\n  const acceptedTypeObj = ACCEPTED_FILE_TYPES.find(t => t.type === f.type);\n  if (!acceptedTypeObj) {\n    icon = <VisaDocumentLow />;\n  } else {\n    icon = acceptedTypeObj.icon;\n  }\n\n  return {\n    file: f,\n    // Create unique ID combining sanitized filename and size for duplicate detection\n    id: `${f.name.replace(/[^a-zA-Z0-9-_]/g, '-')}-${f.size}`,\n    icon,\n  };\n};\n\n/**\n * Assigns numeric rank to file status for sorting.\n * Lower numbers sort first: uploading (1) -> uploaded (2) -> error (3)\n *\n * @param file - File to get status rank for\n * @returns Numeric rank for sorting\n */\nfunction getFileStatusRank(file: UploadFile): number {\n  if (file.uploading) return 1;\n  if (file.uploaded && !file.error) return 2;\n  return 3;\n}\n\n// Column definitions for the upload table, matching dynamic-table ColData pattern\nconst columnData: ColData[] = [\n  { name: 'File name', sortable: true, identifier: true },\n  { name: 'File type', sortable: true },\n  { name: 'Status', sortable: true },\n  { name: 'Upload date', sortable: true },\n  { name: 'Actions', sortable: false, compact: true },\n];\n\n/**\n * Sorts upload files based on the current sort key, using the same SortType\n * conventions as the dynamic-table pattern.\n *\n * @param files - Files to sort\n * @param sortKey - Current sort column and direction\n * @returns Sorted copy of files array\n */\nfunction sortUploadFiles(files: UploadFile[], sortKey: SortKeyType): UploadFile[] {\n  if (sortKey.direction === SortType.NONE) return files;\n\n  const multiplier = sortKey.direction === SortType.ASC ? 1 : -1;\n\n  return [...files].sort((a, b) => {\n    switch (sortKey.column) {\n      case 'File name':\n        return multiplier * a.file.name.localeCompare(b.file.name, undefined, { numeric: true, sensitivity: 'base' });\n      case 'File type':\n        return multiplier * a.file.type.localeCompare(b.file.type, undefined, { numeric: true, sensitivity: 'base' });\n      case 'Status':\n        return multiplier * (getFileStatusRank(a) - getFileStatusRank(b));\n      case 'Upload date': {\n        const aDate = a.uploadDate ? a.uploadDate.getTime() : 0;\n        const bDate = b.uploadDate ? b.uploadDate.getTime() : 0;\n        return multiplier * (aDate - bDate);\n      }\n      default:\n        return 0;\n    }\n  });\n}\n\n/**\n * Multiple file upload with Table display featuring sortable columns and upload date tracking.\n * Files are queued in Dialog for manual upload trigger, then displayed in sortable Table with detailed metadata.\n */\nconst FileUploadWithAlternateDisplay = () => {\n  // Hidden file input reference for programmatic triggering\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  // Refs for managing focus on retry buttons of failed files\n  const retryRefs = useRef<Record<string, (element: HTMLDivElement | null) => void>>({});\n  const retryElements = useRef<Record<string, HTMLDivElement | null>>({});\n\n  // Files that have been uploaded or are uploading\n  const [uploadedFiles, setUploadedFiles] = useState<UploadFile[]>([]);\n\n  // Files awaiting user confirmation in dialog\n  const [queuedFiles, setQueuedFiles] = useState<UploadFile[]>([]);\n\n  // Controls visibility of error section message\n  const [showSectionMessage, setShowSectionMessage] = useState(true);\n\n  // Controls visibility of success flag notification\n  const [showFlag, setShowFlag] = useState(true);\n\n  // Sort state matching dynamic-table pattern, default to ascending on identifying column\n  const [sortKey, setSortKey] = useState<SortKeyType>({ column: 'File name', direction: SortType.ASC });\n\n  /**\n   * Triggers the hidden file input when Select button is clicked.\n   */\n  const handleSelectFilesClick = () => {\n    if (fileInputRef.current) {\n      fileInputRef.current.click();\n    }\n  };\n\n  /**\n   * Handles file selection and adds files to queue.\n   * Important: Files are NOT uploaded immediately - they are queued in dialog.\n   *\n   * @param event - Change event from file input\n   */\n  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const files = event.target.files;\n    if (files && files.length > 0) {\n      const filesArray = Array.from(files);\n\n      const uploadFiles: UploadFile[] = filesArray.map(f => validateFile(f));\n\n      setQueuedFiles((prevQueuedFiles: UploadFile[]) => {\n        const newlyQueuedFiles = uploadFiles\n          // Filter out duplicates based on ID to prevent adding same file twice\n          .filter(file => !prevQueuedFiles.some(f => f.id === file.id));\n\n        return [...prevQueuedFiles, ...newlyQueuedFiles];\n      });\n    }\n  };\n\n  /**\n   * Handles upload button click in dialog.\n   * Closes dialog, timestamps files, and initiates concurrent uploads.\n   */\n  const handleUploadClick = () => {\n    handleCloseDialog();\n\n    setUploadedFiles((oldUploadFiles: UploadFile[]) => {\n      const newUploadFiles = queuedFiles\n        // Filter out files already tracked to prevent re-uploading\n        .filter(file => !oldUploadFiles.some(f => f.id === file.id))\n        .map(f => ({\n          ...f,\n          uploading: true,\n          uploadDate: new Date(), // Record timestamp when upload begins for display in table\n        }));\n\n      newUploadFiles.forEach(newFileItem => {\n        // Replace mockUpload with your actual upload API call\n        mockUpload(newFileItem, {\n          maxFileSize: MAX_FILE_SIZE,\n          acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n        })\n          .then(() => {\n            setUploadedFiles(oldUploadFiles =>\n              oldUploadFiles.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: true, error: undefined } : f\n              )\n            );\n            setShowFlag(true);\n          })\n          .catch((err: Error) => {\n            setUploadedFiles(oldUploadFiles =>\n              oldUploadFiles.map(f =>\n                f.file === newFileItem.file ? { ...f, uploading: false, uploaded: false, error: err.message } : f\n              )\n            );\n            setShowSectionMessage(true);\n          });\n      });\n\n      return [...oldUploadFiles, ...newUploadFiles];\n    });\n  };\n\n  /**\n   * Removes a file from the uploaded files list.\n   * Hides success flag if deleting an errored file.\n   *\n   * @param fileToDelete - File to remove from tracking\n   */\n  const handleDeleteFile = (fileToDelete: UploadFile) => {\n    setUploadedFiles(files => files.filter(file => file.id !== fileToDelete.id));\n    if (fileToDelete.error) {\n      setShowFlag(false);\n    }\n  };\n\n  /**\n   * Removes a file from the queue (before upload).\n   *\n   * @param fileToDelete - File to remove from queue\n   */\n  const handleDeleteQueuedFile = (fileToDelete: UploadFile) => {\n    setQueuedFiles(files => files.filter(file => file.id !== fileToDelete.id));\n  };\n\n  /**\n   * Retries all failed file uploads.\n   */\n  const handleRetryAll = () => {\n    erroredFiles.forEach(f => handleRetryFile(f));\n  };\n\n  /**\n   * Retries upload for a single failed file.\n   *\n   * @param fileToRetry - File with error state to retry\n   */\n  const handleRetryFile = (fileToRetry: UploadFile) => {\n    // Update file state to uploading and clear previous error\n    setUploadedFiles(files =>\n      files.map(f => (f.id === fileToRetry.id ? { ...fileToRetry, error: undefined, uploading: true } : f))\n    );\n    setShowSectionMessage(true);\n\n    mockUpload(fileToRetry, {\n      maxFileSize: MAX_FILE_SIZE,\n      acceptedFileTypes: ACCEPTED_FILE_TYPES.map(t => t.type),\n    })\n      .then(() => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? { ...f, uploading: false, uploaded: true, error: undefined }\n              : f\n          )\n        );\n\n        setShowFlag(true);\n      })\n      .catch(err => {\n        setUploadedFiles(files =>\n          files.map(f =>\n            f.file.name === fileToRetry.file.name && f.file.size === fileToRetry.file.size\n              ? {\n                  ...f,\n                  uploading: false,\n                  uploaded: false,\n                  error: err?.message || 'Error: Failed to upload file to server.',\n                }\n              : f\n          )\n        );\n\n        setShowSectionMessage(true);\n      });\n  };\n\n  // Computed values for UI state\n  const erroredFiles = uploadedFiles.filter(f => !!f.error);\n  const uploadingFiles = uploadedFiles.filter(f => !!f.uploading);\n  const allFilesUploaded =\n    uploadedFiles.length > 0 && uploadedFiles.filter(f => f.uploaded).length === uploadedFiles.length;\n\n  // Create callback refs for retry buttons to enable keyboard navigation to errors\n  erroredFiles.forEach(f => {\n    if (!retryRefs.current[f.id]) {\n      retryRefs.current[f.id] = (element: HTMLDivElement | null) => {\n        retryElements.current[f.id] = element;\n      };\n    }\n  });\n\n  /**\n   * Hides the error section message.\n   */\n  const handleSectionMessageClose = () => {\n    setShowSectionMessage(false);\n  };\n\n  /**\n   * Hides the success flag notification.\n   */\n  const handleFlagClose = () => {\n    setShowFlag(false);\n  };\n\n  /**\n   * Handles dialog close - clears queued files.\n   */\n  const handleCloseDialog = () => {\n    setQueuedFiles([]);\n  };\n\n  /**\n   * Updates the sort key to trigger table re-sorting.\n   *\n   * @param column - Column to sort by\n   * @param direction - Sort direction (ascending or descending)\n   */\n  const sort = (column: ColData, direction: SortType) => {\n    setSortKey({ column: column.name, direction });\n  };\n\n  // Store sorted data and update based on sort key changes\n  const sortedFiles = useMemo(() => {\n    return sortUploadFiles(uploadedFiles, sortKey);\n  }, [uploadedFiles, sortKey]);\n\n  return (\n    <Utility vFlex vFlexCol vGap={25}>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Utility vFlex vFlexCol vGap={16}>\n          <Utility vFlex vFlexCol vGap={8} style={{ maxWidth: '400px' }}>\n            <Typography tag=\"h4\" variant=\"subtitle-1\">\n              Upload files\n            </Typography>\n            {/* Update instructions to match your MAX_FILE_SIZE and ACCEPTED_FILE_TYPES */}\n            <Typography variant=\"label-small\">\n              Choose one or more files to upload, up to 10MB each. Accepted file types are .jpg, .pdf, .docx, and .xlsx.\n            </Typography>\n          </Utility>\n          {/* Hidden file input with multiple file support */}\n          <ScreenReader<'input'>\n            tag={'input'}\n            type=\"file\"\n            hidden\n            multiple\n            ref={fileInputRef}\n            onChange={handleFileChange}\n          ></ScreenReader>\n          <UtilityFragment vAlignSelf=\"start\">\n            <Button colorScheme=\"secondary\" onClick={handleSelectFilesClick}>\n              Select file(s)\n            </Button>\n          </UtilityFragment>\n        </Utility>\n        {/* Always-present live region */}\n        <Utility vFlex vFlexCol vGap={8} role=\"status\" style={{ minHeight: '1rem' }}>\n          {!!uploadingFiles.length && (\n            <Typography variant=\"label-small\">{`Uploading ${uploadingFiles.length} file${uploadingFiles.length > 1 ? 's' : ''}...`}</Typography>\n          )}\n          {/* Error message with clickable file links for keyboard navigation to retry buttons */}\n          {!!erroredFiles.length && showSectionMessage && (\n            <UtilityFragment vMarginVertical={21}>\n              <SectionMessage messageType=\"error\">\n                <MessageIcon messageType=\"error\" />\n                <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                  <SectionMessageContent style={{ wordBreak: 'break-all' }}>\n                    <Typography>The following files have errors:</Typography>\n                    <UtilityFragment vPaddingLeft={20}>\n                      <ul style={{ listStyle: 'initial' }}>\n                        {erroredFiles.map(f => (\n                          <li key={f.file.name + f.file.size}>\n                            <Typography<'a'>\n                              tag=\"a\"\n                              href=\"#\"\n                              onClick={e => {\n                                e.preventDefault();\n                                retryElements.current[f.id]?.focus();\n                              }}\n                            >\n                              {f.file.name}\n                            </Typography>\n                          </li>\n                        ))}\n                      </ul>\n                    </UtilityFragment>\n                    {erroredFiles.length > 1 && (\n                      <UtilityFragment vMarginTop={8}>\n                        <Button colorScheme=\"secondary\" onClick={handleRetryAll}>\n                          Retry all\n                        </Button>\n                      </UtilityFragment>\n                    )}\n                  </SectionMessageContent>\n                </UtilityFragment>\n                <SectionMessageCloseButton onClick={handleSectionMessageClose}>\n                  <VisaCloseTiny />\n                </SectionMessageCloseButton>\n              </SectionMessage>\n            </UtilityFragment>\n          )}\n        </Utility>\n        {/* Table view for uploaded files - displays when files exist */}\n        {!!sortedFiles.length && (\n          <TableWrapper style={{ '--v-table-wrapper-inline-size': '1000px' } as CSSProperties}>\n            <Table\n              alternate\n              style={\n                {\n                  // Use compact spacing matching dynamic-table default\n                  '--v-table-data-padding-block-default': 'var(--v-table-data-padding-block-small)',\n                  '--v-table-data-block-default': 'var(--v-table-data-block-small)',\n                } as CSSProperties\n              }\n            >\n              <ScreenReader tag=\"caption\">\n                File upload table showing file name, type, status, and upload date with sortable columns and action\n                buttons for each file.\n              </ScreenReader>\n              <Thead>\n                <Tr>\n                  {columnData.map((col, index) => {\n                    const sorted = col.name === sortKey.column ? sortKey.direction : SortType.NONE;\n                    return (\n                      <Th\n                        key={index}\n                        scope=\"col\"\n                        style={col.compact ? { inlineSize: '1%' } : undefined}\n                        aria-sort={col.name === sortKey.column ? sortKey.direction : undefined}\n                      >\n                        <Utility vFlex vJustifyContent=\"between\" vAlignItems=\"center\" vGap={4}>\n                          {col.compact ? <ScreenReader>{col.name}</ScreenReader> : col.name}\n                          {col.sortable && (\n                            <Button\n                              iconButton\n                              buttonSize=\"small\"\n                              colorScheme=\"tertiary\"\n                              aria-label={`Sort by ${col.name} ${sorted === SortType.ASC ? 'descending' : 'ascending'}`}\n                              onClick={() => sort(col, sorted === SortType.ASC ? SortType.DESC : SortType.ASC)}\n                            >\n                              {sorted === SortType.ASC ? (\n                                <VisaSortAscendingTiny />\n                              ) : sorted === SortType.DESC ? (\n                                <VisaSortDescendingTiny />\n                              ) : (\n                                <VisaSortableTiny />\n                              )}\n                            </Button>\n                          )}\n                        </Utility>\n                      </Th>\n                    );\n                  })}\n                </Tr>\n              </Thead>\n              <Tbody>\n                {sortedFiles.map(file => (\n                  <UploadRow\n                    key={file.id}\n                    retryRef={retryRefs.current[file.id]}\n                    file={file}\n                    onRetry={() => handleRetryFile(file)}\n                    onDelete={() => handleDeleteFile(file)}\n                  />\n                ))}\n              </Tbody>\n            </Table>\n          </TableWrapper>\n        )}\n      </Utility>\n      {/* Success notification - positioned at bottom right */}\n      <Utility role=\"alert\" vAlignSelf=\"end\">\n        {showFlag && allFilesUploaded && (\n          <Flag messageType=\"success\">\n            <MessageIcon messageType=\"success\" />\n            <FlagContent className=\"v-pl-2 v-pb-2\">Files uploaded successfully.</FlagContent>\n            <FlagCloseButton onClick={handleFlagClose}>\n              <VisaCloseTiny />\n            </FlagCloseButton>\n          </Flag>\n        )}\n      </Utility>\n      {/* Dialog shows when files are queued - opens automatically when queuedFiles has items */}\n      <UploadDialog\n        isOpen={queuedFiles.length > 0}\n        title={UPLOAD_DIALOG_TITLE}\n        description={UPLOAD_DIALOG_DESCRIPTION}\n        queuedFiles={queuedFiles}\n        onSelectFiles={handleSelectFilesClick}\n        onUpload={handleUploadClick}\n        onClose={handleCloseDialog}\n        onDeleteQueuedFile={handleDeleteQueuedFile}\n        dialogId={uploadQueueDialogId}\n      />\n    </Utility>\n  );\n};\n\nexport default FileUploadWithAlternateDisplay;\n"
          },
          "name": "File upload with alternate display"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/file-status-button.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/file-status-button.tsx": "/**\n * Dynamic status indicator that transforms between uploading spinner, success icon, and interactive retry button.\n * Uses forwardRef for focus management; only error state is keyboard-accessible and clickable.\n */\n\nimport React, { forwardRef, type CSSProperties } from 'react';\nimport { ProgressCircular, ScreenReader, Utility } from '@visa/nova-react';\nimport { VisaReloadTiny, VisaSuccessTiny } from '@visa/nova-icons-react';\nimport type { FileStatusButtonProps } from './types';\n\nexport const FileStatusButton = forwardRef<HTMLDivElement, FileStatusButtonProps>(({ uploadFile, onRetry }, ref) => {\n  // Determine current state (mutually exclusive states for clearer logic)\n  const isError = !!uploadFile.error;\n  const isUploading = !!uploadFile.uploading && !uploadFile.error;\n  const isUploaded = !!uploadFile.uploaded && !uploadFile.error && !uploadFile.uploading;\n\n  // Configure content, ARIA attributes, and interactivity based on file state\n  let content: React.ReactNode;\n  let ariaLabel: string | undefined;\n  let role: string | undefined;\n  let tabIndex: number = -1;\n\n  if (isError) {\n    // Error state: Interactive retry button\n    content = <VisaReloadTiny />;\n    ariaLabel = `Retry uploading ${uploadFile.file.name}`;\n    role = 'button';\n    tabIndex = 0; // Keyboard focusable\n  } else if (isUploading) {\n    // Uploading state: Progress spinner (non-interactive)\n    content = (\n      <Utility vMarginHorizontal={11} style={{ '--v-progress-bar-thickness': '2px' } as CSSProperties}>\n        <ProgressCircular indeterminate progressSize={16} />\n        <ScreenReader>{`Uploading ${uploadFile.file.name}`}</ScreenReader>\n      </Utility>\n    );\n    role = 'img';\n    ariaLabel = `Uploading ${uploadFile.file.name}`;\n  } else if (isUploaded) {\n    // Success state: Checkmark icon (non-interactive)\n    content = (\n      <Utility vMarginHorizontal={11} style={{ blockSize: '16px' }}>\n        <VisaSuccessTiny />\n      </Utility>\n    );\n    role = 'img';\n    ariaLabel = `Successfully uploaded ${uploadFile.file.name}`;\n  }\n\n  /**\n   * Handles keyboard activation (Enter/Space) for retry action.\n   * Only active when file has error.\n   *\n   * @param e - Keyboard event\n   */\n  function handleKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {\n    if ((e.key === 'Enter' || e.key === ' ') && isError) {\n      e.preventDefault();\n      onRetry();\n    }\n  }\n\n  return (\n    <div\n      ref={ref}\n      tabIndex={tabIndex}\n      aria-label={ariaLabel}\n      role={role}\n      onClick={isError ? onRetry : undefined}\n      onKeyDown={isError ? handleKeyDown : undefined}\n      className={isError ? 'v-button v-button-tertiary v-button-icon' : ''}\n      style={{\n        ...(!isError && { outline: 'none' }), // No focus outline for non-interactive states (uploading/success)\n      }}\n    >\n      {content}\n    </div>\n  );\n});\n\nFileStatusButton.displayName = 'FileStatusButton';\n"
          },
          "name": "File status button"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/mock-upload.ts"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/mock-upload.ts": "import type { UploadFile } from './types';\n\n/**\n * Configuration options for mock upload.\n */\nexport interface MockUploadOptions {\n  maxFileSize: number; // Maximum file size in bytes\n  acceptedFileTypes: string[]; // Array of accepted MIME types\n}\n\n/**\n * Mock utility simulating file upload with 5-second delay and validation.\n *\n * @param uploadFile - File to upload\n * @param options - Validation options\n * @returns Promise that resolves on success or rejects with error message\n */\nexport const mockUpload = (uploadFile: UploadFile, options: MockUploadOptions): Promise<void> => {\n  return new Promise((resolve, reject) => {\n    // Simulate network delay (5 seconds)\n    setTimeout(() => {\n      let fileError;\n\n      // Validate file size\n      if (uploadFile.file.size > options.maxFileSize) {\n        fileError = 'File size is too large.';\n      }\n\n      // Validate file type\n      if (!options.acceptedFileTypes.includes(uploadFile.file.type)) {\n        fileError = 'File type not accepted.';\n      }\n\n      if (fileError) {\n        reject(new Error(fileError));\n        return;\n      }\n\n      // Simulate successful upload\n      resolve();\n    }, 5000);\n  });\n};\n"
          },
          "name": "Mock upload"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/types.ts"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/types.ts": "import React from 'react';\n\n/**\n * Shared Types for File Upload Patterns\n *\n * Type definitions for data structures and component props used across all file upload pattern variants.\n * Includes UploadFile for tracking file state, and props types for UploadDialog, UploadCard, UploadRow, and FileStatusButton components.\n */\n\n/**\n * Represents a file being tracked in the upload system.\n *\n * @property file - Native File object from browser\n * @property id - Unique identifier combining filename and size for duplicate detection\n * @property icon - React element for file type icon (optional)\n * @property uploaded - True when file has successfully uploaded (optional)\n * @property uploading - True while file is being uploaded (optional)\n * @property error - Error message string if upload failed (optional)\n * @property uploadDate - Timestamp when upload started (optional, used in table display variant)\n */\nexport type UploadFile = {\n  file: File;\n  id: string;\n  icon?: React.ReactElement;\n  uploaded?: boolean;\n  uploading?: boolean;\n  error?: string;\n  uploadDate?: Date;\n};\n\n/**\n * Props for UploadDialog component.\n * Used in manual upload patterns to show file queue before uploading.\n *\n * @property isOpen - Controls dialog visibility\n * @property title - Dialog title text (optional, defaults to \"Upload files\")\n * @property description - Instructional text displayed in dialog\n * @property queuedFiles - Array of files awaiting upload\n * @property onSelectFiles - Callback to open file picker\n * @property onUpload - Callback to initiate upload for queued files\n * @property onClose - Callback to close dialog\n * @property onDeleteQueuedFile - Callback to remove file from queue\n * @property dialogId - Unique ID for dialog element (optional)\n */\nexport type UploadDialogProps = {\n  isOpen: boolean;\n  title?: string;\n  description: string;\n  queuedFiles: UploadFile[];\n  onSelectFiles: () => void;\n  onUpload: () => void;\n  onClose: () => void;\n  onDeleteQueuedFile: (file: UploadFile) => void;\n  dialogId?: string;\n};\n\n/**\n * Props for UploadCard component.\n * Displays file information in card format for list-based upload patterns.\n *\n * @property file - File to display\n * @property renderActions - Render prop function returning action buttons\n */\nexport type UploadCardProps = {\n  file: UploadFile;\n  renderActions: () => React.ReactNode;\n};\n\n/**\n * Props for UploadRow component.\n * Displays file information in table row format for table-based upload patterns.\n *\n * @property file - File to display\n * @property retryRef - Ref for retry button to enable keyboard navigation focus\n * @property onRetry - Callback to retry failed upload\n * @property onDelete - Callback to delete file\n */\nexport type UploadRowProps = {\n  file: UploadFile;\n  retryRef: React.RefObject<HTMLDivElement> | ((element: HTMLDivElement | null) => void);\n  onRetry: () => void;\n  onDelete: () => void;\n};\n\n/**\n * Props for FileStatusButton component.\n * Displays dynamic status indicator that changes based on upload state.\n *\n * @property uploadFile - File to show status for\n * @property onRetry - Callback to retry failed upload\n */\nexport interface FileStatusButtonProps {\n  uploadFile: UploadFile;\n  onRetry: () => void;\n}\n\n/**\n * Column data type definition, matching the dynamic-table pattern.\n *\n * @property compact - (optional) Whether the column should use compact spacing\n * @property identifier - (optional) Whether this column serves as the row identifier\n * @property name - Display name of the column\n * @property sortable - Whether the column supports sorting\n */\nexport type ColData = {\n  compact?: boolean;\n  identifier?: boolean;\n  name: string;\n  sortable: boolean;\n};\n\n/**\n * Sort key type definition.\n *\n * @property column - Name of the column to sort by\n * @property direction - Sort direction (ascending, descending, or none)\n */\nexport type SortKeyType = {\n  column: string;\n  direction: SortType;\n};\n\n/**\n * Sort type constants mapping to aria-sort attribute values.\n */\nexport const SortType = {\n  NONE: 'none',\n  ASC: 'ascending',\n  DESC: 'descending',\n} as const;\nexport type SortType = (typeof SortType)[keyof typeof SortType];\n"
          },
          "name": "Types"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/upload-card.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/upload-card.tsx": "import React from 'react';\nimport { Utility, UtilityFragment, Surface, Typography, ScreenReader } from '@visa/nova-react';\nimport { VisaErrorTiny } from '@visa/nova-icons-react';\nimport type { UploadFile, UploadCardProps } from './types';\n\n/**\n * Generates unique ID for error message to link with aria-describedby.\n *\n * @param file - File to generate error ID for\n * @returns Unique error ID or empty string if no error\n */\nfunction getListItemErrorId(file: UploadFile): string {\n  if (!file.error) {\n    return '';\n  }\n  return `file-list-error-${file.id}`;\n}\n\n/**\n * Card-based file display component showing file icon, name, size, and custom action buttons.\n * Used in list-style upload patterns; includes error state styling and accessible error messaging.\n *\n * @param file - UploadFile object containing file data and state\n * @param renderActions - Render prop function returning action buttons/elements\n */\nexport const UploadCard: React.FC<UploadCardProps> = ({ file, renderActions }) => {\n  const errorId = getListItemErrorId(file);\n  const fileNameId = `${file.id}-name`;\n  const fileSizeId = `${file.id}-size`;\n  const errorMessage = `Error: ${file.error}`;\n  const fileSize = `${(file.file.size / (1024 * 1024)).toFixed(2)} MB`;\n\n  return (\n    <Utility tag=\"li\" vFlex vFlexCol vGap={5}>\n      <UtilityFragment vFlex vJustifyContent=\"between\" vPaddingHorizontal={15} vPaddingVertical={7}>\n        {/* Card container with error state styling */}\n        <Surface\n          style={{\n            border: file.error\n              ? '1px solid var(--palette-messaging-graphics-negative)'\n              : '1px solid var(--v-surface-border-color)',\n            borderRadius: 'var(--theme-border-radius)',\n            wordBreak: 'break-all',\n          }}\n        >\n          {/* File info section with icon, name, and size */}\n          <Utility vFlex vAlignItems=\"center\" vGap={8}>\n            {file.icon}\n            <div>\n              <Typography id={fileNameId} tag=\"h5\" variant=\"label\" aria-describedby={errorId}>\n                {file.file.name}\n              </Typography>\n              <Typography id={fileSizeId} variant=\"label-small\" colorScheme=\"subtle\">\n                {fileSize}\n              </Typography>\n              {/* Hidden error message for screen readers */}\n              <UtilityFragment vHide={!file.error}>\n                <ScreenReader tag=\"span\" id={errorId}>\n                  {errorMessage}\n                </ScreenReader>\n              </UtilityFragment>\n            </div>\n          </Utility>\n          {/* Action buttons area (passed via render prop) */}\n          <Utility vFlex vAlignItems=\"center\" vGap={8}>\n            {renderActions()}\n          </Utility>\n        </Surface>\n      </UtilityFragment>\n      {/* Visible error message below card (aria-hidden since screen reader uses errorId) */}\n      <UtilityFragment\n        vHide={!file.error}\n        vFlex\n        vGap={4}\n        style={{\n          lineHeight: '16px',\n          color: 'var(--palette-messaging-text-negative)',\n        }}\n      >\n        <Typography tag=\"span\" variant=\"label\" aria-hidden>\n          <VisaErrorTiny\n            style={\n              {\n                '--v-icon-primary': 'var(--palette-messaging-text-negative)',\n                '--v-icon-secondary': 'var(--palette-messaging-text-negative)',\n              } as React.CSSProperties\n            }\n          />\n          {errorMessage}\n        </Typography>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Upload card"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/upload-dialog.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/upload-dialog.tsx": "import React, { type CSSProperties, useEffect } from 'react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Divider,\n  Typography,\n  Utility,\n  UtilityFragment,\n  useFocusTrap,\n} from '@visa/nova-react';\n\nimport { VisaCloseTiny, VisaDeleteTiny } from '@visa/nova-icons-react';\n\nimport type { UploadDialogProps } from './types';\nimport { UploadCard } from './upload-card';\n\n/**\n * Dialog component for reviewing and managing queued files before manual upload.\n * Displays file queue with add/remove capabilities and focus trap for keyboard accessibility.\n */\nexport const UploadDialog: React.FC<UploadDialogProps> = ({\n  isOpen,\n  title = 'Upload files',\n  description,\n  queuedFiles,\n  onSelectFiles,\n  onUpload,\n  onClose,\n  onDeleteQueuedFile,\n  dialogId = 'upload-dialog',\n}) => {\n  // Focus trap ensures keyboard navigation stays within dialog when open\n  const { onKeyNavigation, ref: dialogRef } = useFocusTrap();\n\n  // Sync dialog native open/close state with isOpen prop\n  useEffect(() => {\n    if (isOpen) {\n      dialogRef.current?.showModal?.();\n    } else {\n      dialogRef.current?.close?.();\n    }\n  }, [isOpen]);\n  return (\n    <UtilityFragment\n      style={{ maxWidth: '400px', '--v-message-display': 'block', overflowY: 'auto' } as CSSProperties}\n      vPaddingHorizontal={0}\n    >\n      <Dialog\n        aria-describedby={`${dialogId}-description`}\n        aria-labelledby={`${dialogId}-title`}\n        id={dialogId}\n        ref={dialogRef}\n        onKeyDown={e => onKeyNavigation(e, dialogRef.current?.open)}\n      >\n        {/* Close button positioned top-right */}\n        <UtilityFragment style={{ marginInlineEnd: 4, float: 'inline-end' }}>\n          <DialogCloseButton onClick={onClose}>\n            <VisaCloseTiny />\n          </DialogCloseButton>\n        </UtilityFragment>\n        <DialogContent style={{ overflowY: 'visible' }}>\n          {/* Header section with title and description */}\n          <Utility vPaddingHorizontal={24}>\n            <DialogHeader id={`${dialogId}-title`} variant=\"headline-4\">\n              {title}\n            </DialogHeader>\n            <Typography id={`${dialogId}-description`} variant=\"body-3\">\n              {description}\n            </Typography>\n          </Utility>\n          {/* Button to add more files */}\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16} vPaddingHorizontal={24}>\n            <Button colorScheme=\"secondary\" onClick={onSelectFiles}>\n              Select file(s)\n            </Button>\n          </Utility>\n          <UtilityFragment vMarginTop={20}>\n            <Divider dividerType=\"decorative\" />\n          </UtilityFragment>\n\n          {/* File queue list area with minimum height */}\n          <UtilityFragment\n            vPaddingVertical={12}\n            vFlex\n            vFlexCol\n            vGap={8}\n            vPaddingHorizontal={24}\n            style={{ minHeight: 'min(25vh, 266px)' }}\n          >\n            <Utility tag=\"ul\" vFlex vFlexCol vGap={8}>\n              {queuedFiles.map(queuedFile => (\n                <UploadCard\n                  key={queuedFile.id}\n                  file={queuedFile}\n                  renderActions={() => (\n                    <Button\n                      aria-label={`Delete ${queuedFile.file.name}`}\n                      colorScheme=\"tertiary\"\n                      iconButton\n                      onClick={() => onDeleteQueuedFile(queuedFile)}\n                    >\n                      <VisaDeleteTiny />\n                    </Button>\n                  )}\n                />\n              ))}\n            </Utility>\n          </UtilityFragment>\n          <UtilityFragment>\n            <Divider dividerType=\"decorative\" />\n          </UtilityFragment>\n          {/* Action buttons: Upload and Cancel */}\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vPaddingTop={16} vPaddingHorizontal={24}>\n            <Button onClick={onUpload}>Upload</Button>\n            <Button colorScheme=\"secondary\" onClick={onClose}>\n              Cancel\n            </Button>\n          </Utility>\n        </DialogContent>\n      </Dialog>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Upload dialog"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/file-upload/upload-row.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/file-upload/shared/upload-row.tsx": "/**\n * Table row component displaying file information with dynamic status indicators and action buttons.\n * Used in table-based upload patterns; includes focus management for keyboard accessibility when retrying failed uploads.\n */\n\nimport { VisaDeleteTiny, VisaErrorTiny, VisaReloadTiny, VisaSuccessTiny } from '@visa/nova-icons-react';\nimport { Button, ProgressCircular, ScreenReader, Td, Th, Tr, Typography, Utility, UtilityFragment } from '@visa/nova-react';\nimport type { UploadRowProps } from './types';\nimport { useRef, type CSSProperties, type RefObject } from 'react';\n\n/**\n * Generates unique ID for error message to link with aria-describedby.\n *\n * @param fileId - Unique file identifier\n * @returns Error message ID for ARIA linking\n */\nfunction getListItemErrorId(fileId: string) {\n  return `file-list-error-${fileId}`;\n}\n\nexport const UploadRow: React.FC<UploadRowProps> = ({ file, onRetry, retryRef, onDelete }) => {\n  const errorId = getListItemErrorId(file.id);\n  const statusRef = useRef<HTMLDivElement>(null);\n\n  /**\n   * Focuses status cell and retries upload.\n   * Called when retry button clicked in table row to provide visual feedback.\n   */\n  const focusStatusAndRetry = () => {\n    if (statusRef.current) {\n      statusRef.current.focus();\n    }\n    onRetry();\n  };\n\n  return (\n    <Tr>\n      {/* File name cell with error message if applicable */}\n      <Th scope=\"row\">\n        <Utility vFlex vFlexCol vGap={1}>\n          <Typography variant=\"label-large\">{file.file.name}</Typography>\n          {file.error && (\n            <UtilityFragment\n              vFlex\n              vGap={2}\n              style={{\n                color: 'var(--palette-messaging-text-negative)',\n              }}\n            >\n              <Typography tag=\"span\" id={errorId} variant=\"label-small\">\n                <VisaErrorTiny\n                  style={\n                    {\n                      '--v-icon-primary': 'var(--palette-messaging-text-negative)',\n                      '--v-icon-secondary': 'var(--palette-messaging-text-negative)',\n                      blockSize: '14px',\n                      inlineSize: '14px',\n                    } as React.CSSProperties\n                  }\n                />\n                {`Error: ${file.error}`}\n              </Typography>\n            </UtilityFragment>\n          )}\n        </Utility>\n      </Th>\n\n      {/* File type cell */}\n      <Td>{file.file.type}</Td>\n\n      {/* Status cell with dynamic content based on file state */}\n      <Td>\n        <Utility\n          vFlex\n          ref={statusRef}\n          tabIndex={-1}\n          style={{\n            borderRadius: 'var(--v-button-default-border-radius)',\n            maxInlineSize: 'fit-content',\n          }}\n        >\n          {file.uploading && (\n            <Utility style={{ '--v-progress-bar-thickness': '2px' } as CSSProperties}>\n              <ProgressCircular indeterminate progressSize={16} />\n              <ScreenReader>{`Uploading ${file.file.name}`}</ScreenReader>\n            </Utility>\n          )}\n          {file.uploaded && !file.error && (\n            <Utility>\n              <VisaSuccessTiny\n                style={\n                  {\n                    '--v-icon-primary': 'var(--palette-messaging-text-positive)',\n                    '--v-icon-secondary': 'var(--palette-messaging-text-positive)',\n                  } as CSSProperties\n                }\n              />\n              <ScreenReader>Success</ScreenReader>\n            </Utility>\n          )}\n          {!file.uploaded && file.error && (\n            <Utility style={{ display: 'inline-block', blockSize: 'var(--v-icon-tiny-height)' }}>\n              <VisaErrorTiny\n                style={\n                  {\n                    '--v-icon-primary': 'var(--palette-messaging-text-negative)',\n                    '--v-icon-secondary': 'var(--palette-messaging-text-negative)',\n                  } as CSSProperties\n                }\n              />\n              <ScreenReader>Error</ScreenReader>\n            </Utility>\n          )}\n        </Utility>\n      </Td>\n\n      {/* Upload date cell */}\n      <Td>{file.uploadDate ? file.uploadDate.toLocaleString() : ''}</Td>\n\n      {/* Actions cell with retry and delete buttons */}\n      <Td>\n        <Utility vFlex>\n          {/* Show retry button only when file has error */}\n          {!!file.error && (\n            <UtilityFragment vAlignSelf=\"stretch\" style={{ '--v-button-default-block-size': '34px' } as CSSProperties}>\n              <Button\n                ref={retryRef as unknown as RefObject<HTMLButtonElement>}\n                aria-label={`Retry uploading ${file.file.name}`}\n                aria-describedby={`${errorId}`}\n                colorScheme=\"tertiary\"\n                iconButton\n                onClick={() => focusStatusAndRetry()}\n              >\n                <VisaReloadTiny />\n              </Button>\n            </UtilityFragment>\n          )}\n          {/* Delete button always visible */}\n          <UtilityFragment vAlignSelf=\"stretch\" style={{ '--v-button-default-block-size': '34px' } as CSSProperties}>\n            <Button aria-label={`Delete ${file.file.name}`} colorScheme=\"tertiary\" iconButton onClick={onDelete}>\n              <VisaDeleteTiny />\n            </Button>\n          </UtilityFragment>\n        </Utility>\n      </Td>\n    </Tr>\n  );\n};\n"
          },
          "name": "Upload row"
        }
      ],
      "propertySections": [],
      "properties": []
    },
    {
      "name": "wizard",
      "version": "0.0.1",
      "description": "Manages and navigates multi-step processes within your application.",
      "libraryId": null,
      "category": "patterns",
      "exampleSections": [
        {
          "name": "Multi-page wizards",
          "description": "",
          "order": 1
        },
        {
          "name": "Single-page wizards",
          "description": "",
          "order": 2
        },
        {
          "name": "Custom wizards",
          "description": "",
          "order": 3
        },
        {
          "name": "Shared Components",
          "description": "",
          "order": 4
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-page wizards",
          "url": {
            "iframe": "patterns/wizard/horizontal-wizard",
            "github": "apps/workshop/src/examples/patterns/wizard/horizontal-wizard.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/wizard/horizontal-wizard.tsx": "import {\n  MessageIcon,\n  VisaArrowBackTiny,\n  VisaArrowForwardTiny,\n  VisaCheckmarkTiny,\n  VisaChevronRightTiny,\n  VisaCloseTiny,\n  VisaErrorAltTiny,\n  VisaErrorTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Badge,\n  Button,\n  ContentCard,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n  Wizard,\n  WizardStep,\n  useFocusTrap,\n  useWizard,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type ChangeEvent, type RefObject } from 'react';\nimport { ExitDialog } from './shared/exit-dialog';\nimport { SaveFlag } from './shared/save-flag';\nimport { SuccessMessage } from './shared/success-message';\nimport { SummaryPage } from './shared/summary-page';\n\n// Unique ID for wizard elements. Customize this or use React.useId() for dynamic generation.\nconst id = 'horizontal-multi-page-wizard';\nconst navRegionAriaLabel = 'Horizontal multi-page wizard';\n\n/**\n * Step configuration defining wizard structure.\n * Each step requires: label (badge text), title, inputLabel, inputId, and buttonId.\n * The final step (without inputId) is reserved for the summary page.\n */\nconst steps = [\n  {\n    label: '1',\n    title: 'Step 1 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-1-input`,\n    buttonId: `${id}-step-1-button`,\n  },\n  {\n    label: '2',\n    title: 'Step 2 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-2-input`,\n    buttonId: `${id}-step-2-button`,\n  },\n  {\n    label: '3',\n    title: 'Step 3 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-3-input`,\n    buttonId: `${id}-step-3-button`,\n  },\n  {\n    label: '4',\n    title: 'Step 4 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-4-input`,\n    buttonId: `${id}-step-4-button`,\n  },\n  {\n    label: '5',\n    title: 'Step 5 label',\n  },\n];\n\nconst exitDialogId = `${id}-exit-warning-dialog`;\n\nconst DEFAULT_INPUT_VALUES = Array(steps.length).fill('');\n\n/**\n * Multi-step form with horizontal progress indicators, validation, auto-save, and summary review.\n */\nexport const HorizontalWizard = () => {\n  const {\n    currentStep,\n    isStepAvailable,\n    isLastStep,\n    isStepComplete,\n    isStepError,\n    onStepError,\n    onStepChange,\n    onStepComplete,\n    onStepPrevious,\n    onWizardReset,\n  } = useWizard({ length: steps.length });\n\n  // Tracks step changes to trigger focus management in useEffect\n  const [hasWizardStepChanged, setHasWizardStepChanged] = useState(false);\n\n  const { onKeyNavigation, ref: exitDialogRef } = useFocusTrap();\n\n  const [inputValues, setInputValues] = useState(DEFAULT_INPUT_VALUES);\n\n  const [showSavedFlag, setShowSavedFlag] = useState(false);\n  const [formSubmitted, setFormSubmitted] = useState(false);\n  const [visibleErrorMessages, setVisibleErrorMessages] = useState<boolean[]>(Array(steps.length).fill(true));\n\n  // Ref maps for programmatic focus management when navigating or encountering errors\n  const inputRefs = useRef(new Map());\n  function getInputRefMap() {\n    if (!inputRefs.current) {\n      inputRefs.current = new Map();\n    }\n    return inputRefs.current;\n  }\n\n  const buttonRefs = useRef(new Map());\n  function getButtonRefMap() {\n    if (!buttonRefs.current) {\n      buttonRefs.current = new Map();\n    }\n    return buttonRefs.current;\n  }\n\n  const editButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n  // Manages focus after step changes for improved keyboard navigation\n  useEffect(() => {\n    if (!hasWizardStepChanged) {\n      return;\n    }\n    // apply focus to the input field of the current step\n    const inputRefsMap = getInputRefMap();\n    const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n    if (currentStepInputNode) {\n      currentStepInputNode.focus();\n    } else {\n      // focus the first available edit button in the array\n      const firstEditButton = editButtonRefs.current.find(ref => ref !== null);\n      if (firstEditButton) {\n        firstEditButton.focus();\n      }\n    }\n\n    setHasWizardStepChanged(false);\n  }, [hasWizardStepChanged, currentStep]);\n\n  /**\n   * Updates form data for a specific step.\n   *\n   * @param index - Step index to update\n   * @param event - Input change event containing new value\n   */\n  const handleInputChange = (index: number, event: ChangeEvent<HTMLInputElement>) => {\n    const value = event.target.value;\n    const newInputValues = [...inputValues];\n    newInputValues[index] = value;\n    setInputValues(newInputValues);\n  };\n\n  /**\n   * Validates current step and advances to next.\n   * Shows error if validation fails.\n   */\n  const handleClickNext = () => {\n    if (!inputValues[currentStep]) {\n      onStepError(currentStep);\n      // Reset error message visibility for this step\n      const newVisibleErrorMessages = [...visibleErrorMessages];\n      newVisibleErrorMessages[currentStep] = true;\n      setVisibleErrorMessages(newVisibleErrorMessages);\n      // find the input element with the error in the refs map and set focus on it\n      const inputRefsMap = getInputRefMap();\n      const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n      currentStepInputNode.focus();\n      return;\n    }\n\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepComplete(currentStep);\n  };\n\n  /**\n   * Returns to previous step without validation.\n   */\n  const handleClickPrevious = () => {\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepPrevious();\n  };\n\n  /**\n   * Displays save confirmation flag.\n   */\n  const handleSave = () => {\n    setShowSavedFlag(true);\n  };\n\n  /**\n   * Resets wizard to initial state.\n   * Typically called after submission to allow restarting the wizard.\n   */\n  const handleResetWizard = () => {\n    setHasWizardStepChanged(true);\n    setInputValues(DEFAULT_INPUT_VALUES);\n    setFormSubmitted(false);\n    onWizardReset();\n  };\n\n  /**\n   * Collects form data and marks wizard as submitted.\n   * Replace with your API integration.\n   */\n  const handleSubmit = () => {\n    const formValues: { [key: string]: string } = {};\n    steps.forEach((step, i) => {\n      if (!step.inputId) return;\n      formValues[step.inputId] = inputValues[i];\n    });\n    setFormSubmitted(true);\n  };\n\n  /**\n   * Opens exit confirmation dialog.\n   */\n  const handleExit = () => {\n    exitDialogRef.current?.showModal();\n  };\n\n  /**\n   * Hides error section message for a specific step.\n   *\n   * @param stepIndex - Index of the step whose error message should be hidden\n   */\n  const handleErrorMessageClose = (stepIndex: number) => {\n    const newVisibleErrorMessages = [...visibleErrorMessages];\n    newVisibleErrorMessages[stepIndex] = false;\n    setVisibleErrorMessages(newVisibleErrorMessages);\n  };\n\n  /**\n   * Handles direct navigation to a step from the wizard nav or summary page.\n   * Validates current step when navigating forward.\n   *\n   * @param i - Target step index\n   */\n  const handleClickStep = (i: number) => {\n    setHasWizardStepChanged(true);\n\n    // If navigating forward, validate current step like \"Next\"\n    if (i > currentStep) {\n      if (!inputValues[currentStep]) {\n        onStepError(currentStep);\n        const newVisibleErrorMessages = [...visibleErrorMessages];\n        newVisibleErrorMessages[currentStep] = true;\n        setVisibleErrorMessages(newVisibleErrorMessages);\n        // focus input with error\n        const inputRefsMap = getInputRefMap();\n        const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n        if (currentStepInputNode) {\n          currentStepInputNode.focus();\n        }\n        return;\n      }\n      onStepComplete(currentStep);\n      onStepChange(i);\n    } else {\n      onStepChange(i);\n    }\n  };\n\n  /**\n   * Renders the final summary page with review and edit capabilities.\n   */\n  const renderSummaryStep = () => (\n    <SummaryPage\n      steps={steps}\n      inputValues={inputValues}\n      onStepClick={handleClickStep}\n      renderActionButtons={renderActionButtons}\n      maxWidth=\"603px\"\n      editButtonRefs={editButtonRefs.current}\n    />\n  );\n\n  /**\n   * Renders wizard action buttons (Save, Exit, Back, Next, Submit) with conditional visibility.\n   */\n  const renderActionButtons = () => {\n    return (\n      <Utility vMarginTop={40}>\n        <Utility vJustifyContent=\"between\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n          <Utility vJustifyContent=\"start\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <Button onClick={handleSave} colorScheme=\"secondary\">\n              Save\n            </Button>\n            <Button onClick={handleExit} colorScheme=\"tertiary\">\n              Exit\n            </Button>\n          </Utility>\n          <Utility vJustifyContent=\"end\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <UtilityFragment vHide={currentStep === 0}>\n              <Button onClick={handleClickPrevious} colorScheme=\"secondary\">\n                <VisaArrowBackTiny />\n                Back\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep === steps.length - 1}>\n              <Button onClick={handleClickNext}>\n                Next\n                <VisaArrowForwardTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep !== steps.length - 1}>\n              <Button onClick={handleSubmit}>Submit</Button>\n            </UtilityFragment>\n          </Utility>\n        </Utility>\n      </Utility>\n    );\n  };\n\n  if (formSubmitted) {\n    return <SuccessMessage onReset={handleResetWizard} />;\n  }\n\n  return (\n    <Utility vFlex vFlexCol vGap={40} vAlignItems=\"center\">\n      <SaveFlag show={showSavedFlag} onClose={() => setShowSavedFlag(false)} />\n      <UtilityFragment vFlex vJustifyContent=\"center\">\n        <nav aria-label={navRegionAriaLabel} style={{ inlineSize: '100%' }}>\n          <UtilityFragment vJustifyContent=\"center\">\n            <Wizard>\n              {steps.map((step, i) => (\n                <WizardStep\n                  key={`horizontal-wizard-step-${i + 1}`}\n                  aria-current={currentStep === i ? 'step' : undefined}\n                >\n                  {isStepAvailable(i) ? (\n                    <>\n                      <Button\n                        className={`${\n                          currentStep === i\n                            ? 'v-typography-label-large-active v-typography-color-default'\n                            : 'v-typography-label-large'\n                        }`}\n                        colorScheme=\"tertiary\"\n                        aria-label={`${isStepError(i) ? 'Error ' : isStepComplete(i) ? 'Completed ' : `${i + 1} `}${\n                          step.title\n                        }`}\n                        onClick={() => handleClickStep(i)}\n                        id={step.buttonId}\n                        ref={node => {\n                          const map = getButtonRefMap();\n                          if (node) {\n                            // store the node in the inputRefs Map\n                            map.set(step.buttonId, node);\n                          } else {\n                            map.delete(step.buttonId);\n                          }\n                        }}\n                      >\n                        <Utility vFlex vGap={8}>\n                          <Badge\n                            aria-current={i === currentStep ? 'step' : undefined}\n                            active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                            badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                            badgeVariant=\"icon\"\n                            clear={i !== currentStep}\n                            tag=\"span\"\n                          >\n                            {isStepError(i) ? (\n                              <VisaErrorAltTiny />\n                            ) : isStepComplete(i) ? (\n                              <VisaCheckmarkTiny />\n                            ) : (\n                              step.label\n                            )}\n                          </Badge>\n                          <Typography tag=\"span\">{step.title}</Typography>\n                        </Utility>\n                        {i < steps.length - 1 && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n                      </Button>\n                    </>\n                  ) : (\n                    <>\n                      <Utility vFlex vGap={8}>\n                        <Badge\n                          active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                          clear={i !== currentStep}\n                          badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                          badgeVariant=\"icon\"\n                          tag=\"span\"\n                        >\n                          {isStepError(i) ? (\n                            <VisaErrorAltTiny />\n                          ) : isStepComplete(i) ? (\n                            <VisaCheckmarkTiny />\n                          ) : (\n                            step.label\n                          )}\n                        </Badge>\n                        <Typography variant={i === currentStep ? 'label-large-active' : 'label-large'}>\n                          {step.title}\n                        </Typography>\n                      </Utility>\n                      {!isLastStep(i) && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n                    </>\n                  )}\n                </WizardStep>\n              ))}\n            </Wizard>\n          </UtilityFragment>\n        </nav>\n      </UtilityFragment>\n      {currentStep === steps.length - 1 ? (\n        renderSummaryStep()\n      ) : (\n        <Utility style={{ maxInlineSize: '603px', inlineSize: '100%' }}>\n          {steps.slice(0, steps.length - 1).map((step, i) => {\n            return (\n              <Utility key={i} vHide={currentStep !== i}>\n                <UtilityFragment vFlex vFlexCol vGap={24} vPadding={48}>\n                  <ContentCard style={{ boxShadow: 'none' }}>\n                    <Utility vFlex vFlexCol vGap={isStepError(i) ? 16 : 8}>\n                      <Typography variant=\"headline-2\">{step.title}</Typography>\n                      {isStepError(i) && visibleErrorMessages[i] && (\n                        <SectionMessage messageType=\"error\" id=\"section-error-horizontal\">\n                          <MessageIcon messageType=\"error\" />\n                          <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                            <SectionMessageContent>\n                              <Typography>\n                                One or more required fields are missing. Complete all required fields to continue.\n                              </Typography>\n                            </SectionMessageContent>\n                          </UtilityFragment>\n                          <SectionMessageCloseButton onClick={() => handleErrorMessageClose(i)}>\n                            <VisaCloseTiny />\n                          </SectionMessageCloseButton>\n                        </SectionMessage>\n                      )}\n                      <Typography variant=\"body-1\">* Indicates a required field.</Typography>\n                    </Utility>\n                    <Utility vFlex vFlexCol vGap={4}>\n                      <Label htmlFor={step.inputId}>{`* ${step.inputLabel}`}</Label>\n                      <InputContainer>\n                        <Input\n                          aria-describedby={\n                            isStepError(i) ? `section-error-horizontal ${step.inputId}-message` : undefined\n                          }\n                          aria-required=\"true\"\n                          aria-invalid={isStepError(i)}\n                          id={step.inputId}\n                          type=\"text\"\n                          value={inputValues[i]}\n                          onChange={e => handleInputChange(i, e as ChangeEvent<HTMLInputElement>)}\n                          ref={node => {\n                            const map = getInputRefMap();\n                            if (node) {\n                              // store the node in the inputRefs Map\n                              map.set(step.inputId, node);\n                            } else {\n                              map.delete(step.inputId);\n                            }\n                          }}\n                        />\n                      </InputContainer>\n                      {isStepError(i) && (\n                        <InputMessage id={`${step.inputId}-message`}>\n                          <VisaErrorTiny />\n                          This is a required field.\n                        </InputMessage>\n                      )}\n                    </Utility>\n                  </ContentCard>\n                </UtilityFragment>\n                <UtilityFragment vMarginTop={10}>\n                  <Typography variant=\"body-3\">Changes have been automatically saved.</Typography>\n                </UtilityFragment>\n                {renderActionButtons()}\n              </Utility>\n            );\n          })}\n        </Utility>\n      )}\n      <ExitDialog\n        exitDialogId={exitDialogId}\n        exitDialogRef={exitDialogRef as RefObject<HTMLDialogElement>}\n        onKeyNavigation={onKeyNavigation}\n      />\n    </Utility>\n  );\n};\n"
          },
          "name": "Horizontal multi-page wizard"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Multi-page wizards",
          "url": {
            "iframe": "patterns/wizard/vertical-wizard",
            "github": "apps/workshop/src/examples/patterns/wizard/vertical-wizard.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/wizard/vertical-wizard.tsx": "import {\n  MessageIcon,\n  VisaArrowBackTiny,\n  VisaArrowForwardTiny,\n  VisaCheckmarkTiny,\n  VisaCloseTiny,\n  VisaErrorAltTiny,\n  VisaErrorTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Badge,\n  Button,\n  ContentCard,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n  Wizard,\n  WizardStep,\n  useFocusTrap,\n  useWizard,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type ChangeEvent, type RefObject } from 'react';\nimport { ExitDialog } from './shared/exit-dialog';\nimport { SaveFlag } from './shared/save-flag';\nimport { SuccessMessage } from './shared/success-message';\nimport { SummaryPage } from './shared/summary-page';\n\n// Unique ID for wizard elements. Customize this or use React.useId() for dynamic generation.\nconst id = 'vertical-multi-page-wizard';\nconst navRegionAriaLabel = 'Vertical multi-page wizard';\n\n/**\n * Step configuration defining wizard structure.\n * Each step requires: label (badge text), title, inputLabel, inputId, and buttonId.\n * The final step (without inputId) is reserved for the summary page.\n */\nconst steps = [\n  {\n    label: '1',\n    title: 'Step 1 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-1-input`,\n    buttonId: `${id}-step-1-button`,\n  },\n  {\n    label: '2',\n    title: 'Step 2 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-2-input`,\n    buttonId: `${id}-step-2-button`,\n  },\n  {\n    label: '3',\n    title: 'Step 3 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-3-input`,\n    buttonId: `${id}-step-3-button`,\n  },\n  {\n    label: '4',\n    title: 'Step 4 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-4-input`,\n    buttonId: `${id}-step-4-button`,\n  },\n  {\n    label: '5',\n    title: 'Step 5 label',\n  },\n];\n\nconst exitDialogId = `${id}-exit-warning-dialog`;\n\nconst DEFAULT_INPUT_VALUES = Array(steps.length).fill('');\n\n/**\n * Multi-step form with vertical sidebar navigation, validation, auto-save, and summary review.\n */\nexport const VerticalWizard = () => {\n  const {\n    currentStep,\n    isStepAvailable,\n    isStepComplete,\n    isStepError,\n    onStepError,\n    onStepChange,\n    onStepComplete,\n    onStepPrevious,\n    onWizardReset,\n  } = useWizard({ length: steps.length });\n\n  // Tracks step changes to trigger focus management in useEffect\n  const [hasWizardStepChanged, setHasWizardStepChanged] = useState(false);\n\n  const { onKeyNavigation, ref: exitDialogRef } = useFocusTrap();\n\n  const [inputValues, setInputValues] = useState(DEFAULT_INPUT_VALUES);\n\n  const [showSavedFlag, setShowSavedFlag] = useState(false);\n  const [formSubmitted, setFormSubmitted] = useState(false);\n  const [visibleErrorMessages, setVisibleErrorMessages] = useState<boolean[]>(Array(steps.length).fill(true));\n\n  // Ref maps for programmatic focus management when navigating or encountering errors\n  const inputRefs = useRef(new Map());\n  function getInputRefMap() {\n    if (!inputRefs.current) {\n      inputRefs.current = new Map();\n    }\n    return inputRefs.current;\n  }\n\n  const buttonRefs = useRef(new Map());\n  function getButtonRefMap() {\n    if (!buttonRefs.current) {\n      buttonRefs.current = new Map();\n    }\n    return buttonRefs.current;\n  }\n\n  const editButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n  // Manages focus after step changes for improved keyboard navigation\n  useEffect(() => {\n    if (!hasWizardStepChanged) {\n      return;\n    }\n    // apply focus to the input field of the current step\n    const inputRefsMap = getInputRefMap();\n    const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n    if (currentStepInputNode) {\n      currentStepInputNode.focus();\n    } else {\n      // focus the first available edit button in the array\n      const firstEditButton = editButtonRefs.current.find(ref => ref !== null);\n      if (firstEditButton) {\n        firstEditButton.focus();\n      }\n    }\n\n    setHasWizardStepChanged(false);\n  }, [hasWizardStepChanged, currentStep]);\n\n  /**\n   * Updates form data for a specific step.\n   *\n   * @param index - Step index to update\n   * @param event - Input change event containing new value\n   */\n  const handleInputChange = (index: number, event: ChangeEvent<HTMLInputElement>) => {\n    const value = event.target.value;\n    const newInputValues = [...inputValues];\n    newInputValues[index] = value;\n    setInputValues(newInputValues);\n  };\n\n  /**\n   * Validates current step and advances to next.\n   * Shows error if validation fails.\n   */\n  const handleClickNext = () => {\n    if (!inputValues[currentStep]) {\n      onStepError(currentStep);\n      // Reset error message visibility for this step\n      const newVisibleErrorMessages = [...visibleErrorMessages];\n      newVisibleErrorMessages[currentStep] = true;\n      setVisibleErrorMessages(newVisibleErrorMessages);\n      // find the input element with the error in the refs map and set focus on it\n      const inputRefsMap = getInputRefMap();\n      const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n      currentStepInputNode.focus();\n      return;\n    }\n\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepComplete(currentStep);\n  };\n\n  /**\n   * Returns to previous step without validation.\n   */\n  const handleClickPrevious = () => {\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepPrevious();\n  };\n\n  /**\n   * Displays save confirmation flag.\n   */\n  const handleSave = () => {\n    setShowSavedFlag(true);\n  };\n\n  /**\n   * Resets wizard to initial state.\n   * Typically called after submission to allow restarting the wizard.\n   */\n  const handleResetWizard = () => {\n    setHasWizardStepChanged(true);\n    setInputValues(DEFAULT_INPUT_VALUES);\n    setFormSubmitted(false);\n    onWizardReset();\n  };\n\n  /**\n   * Collects form data and marks wizard as submitted.\n   * Replace with your API integration.\n   */\n  const handleSubmit = () => {\n    const formValues: { [key: string]: string } = {};\n    steps.forEach((step, i) => {\n      if (!step.inputId) return;\n      formValues[step.inputId] = inputValues[i];\n    });\n    setFormSubmitted(true);\n  };\n\n  /**\n   * Opens exit confirmation dialog.\n   */\n  const handleExit = () => {\n    exitDialogRef.current?.showModal();\n  };\n\n  /**\n   * Hides error section message for a specific step.\n   *\n   * @param stepIndex - Index of the step whose error message should be hidden\n   */\n  const handleErrorMessageClose = (stepIndex: number) => {\n    const newVisibleErrorMessages = [...visibleErrorMessages];\n    newVisibleErrorMessages[stepIndex] = false;\n    setVisibleErrorMessages(newVisibleErrorMessages);\n  };\n\n  /**\n   * Handles direct navigation to a step from the wizard nav or summary page.\n   * Validates current step when navigating forward.\n   *\n   * @param i - Target step index\n   */\n  const handleClickStep = (i: number) => {\n    setHasWizardStepChanged(true);\n\n    // If navigating forward, validate current step like \"Next\"\n    if (i > currentStep) {\n      if (!inputValues[currentStep]) {\n        onStepError(currentStep);\n        const newVisibleErrorMessages = [...visibleErrorMessages];\n        newVisibleErrorMessages[currentStep] = true;\n        setVisibleErrorMessages(newVisibleErrorMessages);\n        // focus input with error\n        const inputRefsMap = getInputRefMap();\n        const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n        if (currentStepInputNode) {\n          currentStepInputNode.focus();\n        }\n        return;\n      }\n      onStepComplete(currentStep);\n      onStepChange(i);\n    } else {\n      onStepChange(i);\n    }\n  };\n\n  /**\n   * Renders the final summary page with review and edit capabilities.\n   */\n  const renderSummaryStep = () => (\n    <SummaryPage\n      steps={steps}\n      inputValues={inputValues}\n      onStepClick={handleClickStep}\n      maxWidth=\"603px\"\n      editButtonRefs={editButtonRefs.current}\n    />\n  );\n\n  /**\n   * Renders wizard action buttons (Save, Exit, Back, Next, Submit) with conditional visibility.\n   */\n  const renderActionButtons = () => {\n    return (\n      <Utility vMarginTop={40}>\n        <Utility vJustifyContent=\"between\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n          <Utility vJustifyContent=\"start\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <Button onClick={handleSave} colorScheme=\"secondary\">\n              Save\n            </Button>\n            <Button onClick={handleExit} colorScheme=\"tertiary\">\n              Exit\n            </Button>\n          </Utility>\n          <Utility vFlexGrow vJustifyContent=\"end\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <UtilityFragment vHide={currentStep === 0}>\n              <Button onClick={handleClickPrevious} colorScheme=\"secondary\">\n                <VisaArrowBackTiny />\n                Back\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep === steps.length - 1}>\n              <Button onClick={handleClickNext}>\n                Next\n                <VisaArrowForwardTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep !== steps.length - 1}>\n              <Button onClick={handleSubmit}>Submit</Button>\n            </UtilityFragment>\n          </Utility>\n        </Utility>\n      </Utility>\n    );\n  };\n\n  if (formSubmitted) {\n    return <SuccessMessage onReset={handleResetWizard} />;\n  }\n\n  return (\n    <Utility vFlex vGap={40} vFlexRow vFlexWrap style={{ margin: '0 auto', maxInlineSize: '878px' }}>\n      <nav aria-label={navRegionAriaLabel} style={{ maxInlineSize: '235px', inlineSize: '100%' }}>\n        <Wizard vertical>\n          {steps.map((step, i) => (\n            <WizardStep key={`horizontal-wizard-step-${i + 1}`} aria-current={currentStep === i ? 'step' : undefined}>\n              {isStepAvailable(i) ? (\n                <>\n                  <Button\n                    className={`${\n                      currentStep === i\n                        ? 'v-typography-label-large-active v-typography-color-default'\n                        : 'v-typography-label-large'\n                    }`}\n                    colorScheme=\"tertiary\"\n                    aria-label={`${isStepError(i) ? 'Error ' : isStepComplete(i) ? 'Completed ' : `${i + 1} `}${\n                      step.title\n                    }`}\n                    onClick={() => handleClickStep(i)}\n                    id={step.buttonId}\n                    ref={node => {\n                      const map = getButtonRefMap();\n                      if (node) {\n                        // store the node in the inputRefs Map\n                        map.set(step.buttonId, node);\n                      } else {\n                        map.delete(step.buttonId);\n                      }\n                    }}\n                  >\n                    <Badge\n                      aria-current={i === currentStep ? 'step' : undefined}\n                      active={currentStep === i && !isStepError(i) && !isStepComplete(i)}\n                      badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                      badgeVariant=\"icon\"\n                      clear={i !== currentStep}\n                      tag=\"span\"\n                    >\n                      {isStepError(i) ? <VisaErrorAltTiny /> : isStepComplete(i) ? <VisaCheckmarkTiny /> : step.label}\n                    </Badge>\n                    <Typography tag=\"span\">{step.title}</Typography>\n                  </Button>\n                </>\n              ) : (\n                <>\n                  <Badge\n                    active={currentStep === i && !isStepError(i) && !isStepComplete(i)}\n                    clear={i !== currentStep}\n                    badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                    badgeVariant=\"icon\"\n                    tag=\"span\"\n                  >\n                    {isStepError(i) ? <VisaErrorAltTiny /> : isStepComplete(i) ? <VisaCheckmarkTiny /> : step.label}\n                  </Badge>\n                  <Typography variant={i === currentStep ? 'label-large-active' : 'label-large'}>\n                    {step.title}\n                  </Typography>\n                </>\n              )}\n            </WizardStep>\n          ))}\n        </Wizard>\n      </nav>\n      <Utility vFlex vFlexCol vGap={12} vFlexGrow style={{ maxInlineSize: '603px' }}>\n        <SaveFlag show={showSavedFlag} onClose={() => setShowSavedFlag(false)} />\n        {steps.slice(0, steps.length - 1).map((step, i) => {\n          return (\n            <Utility key={i} vHide={currentStep !== i}>\n              <UtilityFragment vFlex vFlexCol vGap={24} vPadding={48}>\n                <ContentCard style={{ boxShadow: 'none' }}>\n                  <Utility vFlex vFlexCol vGap={isStepError(i) ? 16 : 8}>\n                    <Typography variant=\"headline-2\">{step.title}</Typography>\n                    {isStepError(i) && visibleErrorMessages[i] && (\n                      <SectionMessage messageType=\"error\" id=\"step-error-vertical\">\n                        <MessageIcon messageType=\"error\" />\n                        <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                          <SectionMessageContent>\n                            <Typography>\n                              One or more required fields are missing. Complete all required fields to continue.\n                            </Typography>\n                          </SectionMessageContent>\n                        </UtilityFragment>\n                        <SectionMessageCloseButton onClick={() => handleErrorMessageClose(i)}>\n                          <VisaCloseTiny />\n                        </SectionMessageCloseButton>\n                      </SectionMessage>\n                    )}\n                    <Typography variant=\"body-1\">* Indicates a required field.</Typography>\n                  </Utility>\n                  <Utility vFlex vFlexCol vGap={4}>\n                    <Label htmlFor={step.inputId}>{`* ${step.inputLabel}`}</Label>\n                    <InputContainer>\n                      <Input\n                        aria-describedby={isStepError(i) ? `step-error-vertical ${step.inputId}-message` : undefined}\n                        aria-required=\"true\"\n                        aria-invalid={isStepError(i)}\n                        id={step.inputId}\n                        type=\"text\"\n                        value={inputValues[i]}\n                        onChange={e => handleInputChange(i, e as ChangeEvent<HTMLInputElement>)}\n                        ref={node => {\n                          const map = getInputRefMap();\n                          if (node) {\n                            // store the node in the inputRefs Map\n                            map.set(step.inputId, node);\n                          } else {\n                            map.delete(step.inputId);\n                          }\n                        }}\n                      />\n                    </InputContainer>\n                    {isStepError(i) && (\n                      <InputMessage id={`${step.inputId}-message`}>\n                        <VisaErrorTiny />\n                        This is a required field.\n                      </InputMessage>\n                    )}\n                  </Utility>\n                </ContentCard>\n              </UtilityFragment>\n              <UtilityFragment vMarginTop={10}>\n                <Typography variant=\"body-3\">Changes have been automatically saved.</Typography>\n              </UtilityFragment>\n            </Utility>\n          );\n        })}\n        {currentStep === steps.length - 1 && renderSummaryStep()}\n        {renderActionButtons()}\n      </Utility>\n      <ExitDialog\n        exitDialogId={exitDialogId}\n        exitDialogRef={exitDialogRef as RefObject<HTMLDialogElement>}\n        onKeyNavigation={onKeyNavigation}\n      />\n    </Utility>\n  );\n};\n"
          },
          "name": "Vertical multi-page wizard"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Single-page wizards",
          "url": {
            "iframe": "patterns/wizard/single-page-wizard",
            "github": "apps/workshop/src/examples/patterns/wizard/single-page-wizard.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/wizard/single-page-wizard.tsx": "import {\n  MessageIcon,\n  VisaArrowBackTiny,\n  VisaArrowForwardTiny,\n  VisaCheckmarkTiny,\n  VisaChevronDownTiny,\n  VisaChevronRightTiny,\n  VisaCloseTiny,\n  VisaErrorAltTiny,\n  VisaErrorTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Badge,\n  Button,\n  Divider,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n  Wizard,\n  WizardStep,\n  useFocusTrap,\n  useWizard,\n  useAccordion,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties, type ChangeEvent, type RefObject } from 'react';\nimport { ExitDialog } from './shared/exit-dialog';\nimport { SaveFlag } from './shared/save-flag';\nimport { SuccessMessage } from './shared/success-message';\nimport { SummaryPage } from './shared/summary-page';\n\n// Unique ID for wizard elements. Customize this or use React.useId() for dynamic generation.\nconst id = 'single-page-wizard';\nconst navRegionAriaLabel = 'Single page wizard';\n\n/**\n * Step configuration defining wizard structure.\n * Each step requires: label (badge text), title, inputLabel, inputId, and buttonId.\n * The final step (without inputId) is reserved for the summary page.\n */\nconst steps = [\n  {\n    label: '1',\n    title: 'Step 1 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-1-input`,\n    buttonId: `${id}-step-1-button`,\n  },\n  {\n    label: '2',\n    title: 'Step 2 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-2-input`,\n    buttonId: `${id}-step-2-button`,\n  },\n  {\n    label: '3',\n    title: 'Step 3 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-3-input`,\n    buttonId: `${id}-step-3-button`,\n  },\n  {\n    label: '4',\n    title: 'Step 4 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-4-input`,\n    buttonId: `${id}-step-4-button`,\n  },\n  {\n    label: '5',\n    title: 'Step 5 label',\n  },\n];\n\nconst exitDialogId = `${id}-exit-warning-dialog`;\n\nconst DEFAULT_INPUT_VALUES = Array(steps.length).fill('');\n\n/**\n * Single-page form with accordion-based steps, validation, auto-save, and summary review.\n */\nexport const SinglePageWizard = () => {\n  const {\n    currentStep,\n    isStepAvailable,\n    isStepComplete,\n    isStepError,\n    onStepError,\n    onStepChange,\n    onStepComplete,\n    onStepPrevious,\n    onWizardReset,\n  } = useWizard({ length: steps.length });\n\n  // Tracks step changes to trigger focus management in useEffect\n  const [hasWizardStepChanged, setHasWizardStepChanged] = useState(false);\n\n  const { onKeyNavigation, ref: exitDialogRef } = useFocusTrap();\n\n  const [inputValues, setInputValues] = useState(DEFAULT_INPUT_VALUES);\n\n  const [showSavedFlag, setShowSavedFlag] = useState(false);\n  const [formSubmitted, setFormSubmitted] = useState(false);\n  const [visibleErrorMessages, setVisibleErrorMessages] = useState<boolean[]>(Array(steps.length).fill(true));\n\n  // Controls which accordion panels are expanded. Synchronized with wizard step navigation.\n  const { isIndexExpanded, toggleIndexExpanded } = useAccordion({\n    defaultExpanded: [0],\n  });\n\n  // Ref maps for programmatic focus management when navigating or encountering errors\n  const inputRefs = useRef(new Map());\n  function getInputRefMap() {\n    if (!inputRefs.current) {\n      inputRefs.current = new Map();\n    }\n    return inputRefs.current;\n  }\n\n  const buttonRefs = useRef(new Map());\n  function getButtonRefMap() {\n    if (!buttonRefs.current) {\n      buttonRefs.current = new Map();\n    }\n    return buttonRefs.current;\n  }\n\n  // Manages focus after step changes for improved keyboard navigation\n  useEffect(() => {\n    if (!hasWizardStepChanged) {\n      return;\n    }\n    // apply focus if the currentStep has changed\n    // (and the wizard has been interacted with)\n    const buttonRefsMap = getButtonRefMap();\n    const currentStepButtonNode = buttonRefsMap.get(steps[currentStep].buttonId);\n    if (currentStepButtonNode instanceof HTMLElement) {\n      // For details/summary, we need to focus the summary element\n      const summaryElement = currentStepButtonNode.querySelector('summary');\n      if (summaryElement) {\n        summaryElement.focus();\n      } else {\n        currentStepButtonNode.focus();\n      }\n    }\n  }, [hasWizardStepChanged, currentStep]);\n\n  /**\n   * Updates form data for a specific step.\n   *\n   * @param index - Step index to update\n   * @param event - Input change event containing new value\n   */\n  const handleInputChange = (index: number, event: ChangeEvent<HTMLInputElement>) => {\n    const value = event.target.value;\n    const newInputValues = [...inputValues];\n    newInputValues[index] = value;\n    setInputValues(newInputValues);\n  };\n\n  /**\n   * Validates current step, advances to next, and manages accordion expansion.\n   */\n  const handleClickNext = () => {\n    if (!inputValues[currentStep]) {\n      onStepError(currentStep);\n      // Reset error message visibility for this step\n      const newVisibleErrorMessages = [...visibleErrorMessages];\n      newVisibleErrorMessages[currentStep] = true;\n      setVisibleErrorMessages(newVisibleErrorMessages);\n      // find the input element with the error in the refs map and set focus on it\n      const inputRefsMap = getInputRefMap();\n      const errorStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n      errorStepInputNode.focus();\n      return;\n    }\n\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepComplete(currentStep);\n\n    toggleIndexExpanded(currentStep);\n    toggleIndexExpanded(currentStep + 1);\n  };\n\n  /**\n   * Returns to previous step and manages accordion expansion.\n   */\n  const handleClickPrevious = () => {\n    setShowSavedFlag(false);\n\n    toggleIndexExpanded(currentStep);\n    toggleIndexExpanded(currentStep - 1);\n\n    onStepPrevious();\n  };\n\n  /**\n   * Displays save confirmation flag.\n   */\n  const handleSave = () => {\n    setShowSavedFlag(true);\n  };\n\n  /**\n   * Resets wizard and accordion state to initial state.\n   */\n  const handleResetWizard = () => {\n    setHasWizardStepChanged(true);\n    setInputValues(DEFAULT_INPUT_VALUES);\n    setFormSubmitted(false);\n\n    steps.forEach((_, index) => {\n      if (isIndexExpanded(index)) {\n        toggleIndexExpanded(index);\n      }\n    });\n    toggleIndexExpanded(0);\n\n    onWizardReset();\n  };\n\n  /**\n   * Collects form data and marks wizard as submitted.\n   */\n  const handleSubmit = () => {\n    const formValues: { [key: string]: string } = {};\n    steps.forEach((step, i) => {\n      if (!step.inputId) return;\n      formValues[step.inputId] = inputValues[i];\n    });\n    setFormSubmitted(true);\n  };\n\n  /**\n   * Opens exit confirmation dialog.\n   */\n  const handleExit = () => {\n    exitDialogRef.current?.showModal();\n  };\n\n  /**\n   * Hides error section message for a specific step.\n   *\n   * @param stepIndex - Index of the step whose error message should be hidden\n   */\n  const handleErrorMessageClose = (stepIndex: number) => {\n    const newVisibleErrorMessages = [...visibleErrorMessages];\n    newVisibleErrorMessages[stepIndex] = false;\n    setVisibleErrorMessages(newVisibleErrorMessages);\n  };\n\n  /**\n   * Handles direct navigation to a step from accordion headings or summary page.\n   * Validates current step when navigating forward and manages accordion panels.\n   *\n   * @param i - Target step index\n   */\n  const handleClickStep = (i: number) => {\n    setHasWizardStepChanged(true);\n\n    // If navigating forward, validate current step like \"Next\"\n    if (i > currentStep) {\n      if (!inputValues[currentStep]) {\n        onStepError(currentStep);\n        const newVisibleErrorMessages = [...visibleErrorMessages];\n        newVisibleErrorMessages[currentStep] = true;\n        setVisibleErrorMessages(newVisibleErrorMessages);\n        // focus input with error\n        const inputRefsMap = getInputRefMap();\n        const errorStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n        if (errorStepInputNode) {\n          errorStepInputNode.focus();\n        }\n        return;\n      }\n      onStepComplete(currentStep);\n    }\n\n    // Only toggle and change step if validation passes or navigating backward\n    requestAnimationFrame(() => {\n      // Close all other steps\n      steps.forEach((_, index) => {\n        if (index !== i && isIndexExpanded(index)) {\n          toggleIndexExpanded(index);\n        }\n      });\n\n      toggleIndexExpanded(i);\n\n      onStepChange(i);\n    });\n  };\n\n  /**\n   * Renders wizard action buttons (Save, Exit, Back, Next, Submit) with conditional visibility.\n   */\n  const renderActionButtons = () => {\n    return (\n      <Utility vPaddingVertical={12} vPaddingHorizontal={40}>\n        <Utility vFlex vFlexWrap vJustifyContent=\"between\" vColGap={24} vRowGap={16}>\n          <Utility vJustifyContent=\"start\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <Button onClick={handleSave} colorScheme=\"secondary\">\n              Save\n            </Button>\n            <Button onClick={handleExit} colorScheme=\"tertiary\">\n              Exit\n            </Button>\n          </Utility>\n          <Utility vFlexGrow vJustifyContent=\"end\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n            <UtilityFragment vHide={currentStep === 0}>\n              <Button onClick={handleClickPrevious} colorScheme=\"secondary\">\n                <VisaArrowBackTiny />\n                Back\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep === steps.length - 1}>\n              <Button onClick={handleClickNext}>\n                Next\n                <VisaArrowForwardTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep !== steps.length - 1}>\n              <Button onClick={handleSubmit}>Submit</Button>\n            </UtilityFragment>\n          </Utility>\n        </Utility>\n      </Utility>\n    );\n  };\n\n  /**\n   * Renders the final summary page with review and edit capabilities.\n   */\n  const renderSummaryStep = () => (\n    <SummaryPage\n      steps={steps}\n      inputValues={inputValues}\n      onStepClick={handleClickStep}\n      vPaddingHorizontal={40}\n      surfaceProps={{}}\n      containerProps={{ vFlexGrow: true }}\n    />\n  );\n\n  if (formSubmitted) {\n    return <SuccessMessage onReset={handleResetWizard} />;\n  }\n  return (\n    <nav aria-label={navRegionAriaLabel}>\n      <UtilityFragment vFlex vFlexCol vGap={16}>\n        <Wizard tag=\"div\">\n          <SaveFlag show={showSavedFlag} onClose={() => setShowSavedFlag(false)} />\n          {steps.map((step, i) => (\n            <WizardStep\n              element={\n                <Accordion tag=\"details\" open={isIndexExpanded(i)} tabIndex={isStepAvailable(i) ? undefined : -1} />\n              }\n              key={`${id}-step-${i + 1}`}\n              aria-current={isIndexExpanded(i) ? 'step' : undefined}\n            >\n              <UtilityFragment vFlex vJustifyContent=\"between\">\n                <AccordionHeading\n                  aria-controls={`${id}-panel-${i}`}\n                  aria-expanded={isIndexExpanded(i)}\n                  buttonSize=\"large\"\n                  colorScheme=\"secondary\"\n                  aria-label={`${isStepError(i) ? 'Error ' : isStepComplete(i) ? 'Completed ' : `${i + 1} `}${\n                    step.title\n                  }`}\n                  disabled={!isStepAvailable(i)}\n                  id={`${id}-${i}`}\n                  onClick={e => {\n                    e.preventDefault();\n                    handleClickStep(i);\n                  }}\n                  ref={node => {\n                    const map = getButtonRefMap();\n                    if (node) {\n                      map.set(step.buttonId, node);\n                    } else {\n                      map.delete(step.buttonId);\n                    }\n                  }}\n                  tag=\"summary\"\n                >\n                  <Utility vAlignItems=\"center\" vFlex vGap={6}>\n                    <Badge\n                      aria-current={i === currentStep ? 'step' : undefined}\n                      active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                      badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                      clear={i !== currentStep}\n                      badgeVariant=\"icon\"\n                      tag=\"span\"\n                      style={{ '--v-badge-disabled-background': 'var(--v-badge-subtle-icon-color)' } as CSSProperties}\n                    >\n                      {isStepError(i) ? (\n                        <VisaErrorAltTiny aria-hidden=\"false\" aria-label=\"error icon\" />\n                      ) : isStepComplete(i) ? (\n                        <VisaCheckmarkTiny aria-hidden=\"false\" aria-label=\"check mark icon\" />\n                      ) : (\n                        step.label\n                      )}\n                    </Badge>\n                    <Typography\n                      tag=\"span\"\n                      colorScheme={\n                        i === currentStep && !isStepError(i) && !isStepComplete(i)\n                          ? 'active'\n                          : isStepAvailable(i)\n                            ? undefined\n                            : 'subtle'\n                      }\n                    >\n                      {step.title}\n                    </Typography>\n                  </Utility>\n                  <AccordionToggleIcon\n                    accordionOpen={isIndexExpanded(i)}\n                    elementClosed={<VisaChevronRightTiny rtl />}\n                    elementOpen={<VisaChevronDownTiny />}\n                  />\n                </AccordionHeading>\n              </UtilityFragment>\n              <UtilityFragment vPaddingVertical={0} vPaddingHorizontal={0}>\n                <AccordionPanel aria-hidden={!isIndexExpanded(i)} id={`${id}-panel-${i}`}>\n                  {i !== steps.length - 1 ? (\n                    <Utility vPaddingVertical={12} vFlex vFlexCol vJustifyContent=\"between\">\n                      <Utility vPaddingVertical={12} vPaddingHorizontal={40} vFlex vFlexCol vGap={4}>\n                        {isStepError(i) && visibleErrorMessages[i] && (\n                          <UtilityFragment vMarginBottom={16}>\n                            <SectionMessage messageType=\"error\" id=\"step-error-single-page\">\n                              <MessageIcon messageType=\"error\" />\n                              <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                                <SectionMessageContent>\n                                  <Typography>\n                                    One or more required fields are missing. Complete all required fields to continue.\n                                  </Typography>\n                                </SectionMessageContent>\n                              </UtilityFragment>\n                              <SectionMessageCloseButton onClick={() => handleErrorMessageClose(i)}>\n                                <VisaCloseTiny />\n                              </SectionMessageCloseButton>\n                            </SectionMessage>\n                          </UtilityFragment>\n                        )}\n                        <UtilityFragment vMarginBottom={16}>\n                          <Typography tag=\"p\">* Indicates a required field.</Typography>\n                        </UtilityFragment>\n                        <Label htmlFor={step.inputId}>{`* ${step.inputLabel}`}</Label>\n                        <InputContainer>\n                          <Input\n                            aria-describedby={\n                              isStepError(i) ? `step-error-single-page ${step.inputId}-message` : undefined\n                            }\n                            aria-required=\"true\"\n                            aria-invalid={isStepError(i)}\n                            id={step.inputId}\n                            type=\"text\"\n                            value={inputValues[i]}\n                            onChange={e => handleInputChange(i, e as ChangeEvent<HTMLInputElement>)}\n                            ref={node => {\n                              const map = getInputRefMap();\n                              if (node) {\n                                map.set(step.inputId, node);\n                              } else {\n                                map.delete(step.inputId);\n                              }\n                            }}\n                          />\n                        </InputContainer>\n                        {isStepError(i) && (\n                          <InputMessage id={`${step.inputId}-message`}>\n                            <VisaErrorTiny />\n                            This is a required field.\n                          </InputMessage>\n                        )}\n                      </Utility>\n                      <UtilityFragment vMarginVertical={12}>\n                        <Divider dividerType=\"decorative\" />\n                      </UtilityFragment>\n                      {renderActionButtons()}\n                    </Utility>\n                  ) : (\n                    <Utility vPaddingVertical={12} vFlex vFlexCol vJustifyContent=\"between\">\n                      {renderSummaryStep()}\n                      <UtilityFragment vMarginVertical={12}>\n                        <Divider dividerType=\"decorative\" />\n                      </UtilityFragment>\n                      {renderActionButtons()}\n                    </Utility>\n                  )}\n                </AccordionPanel>\n              </UtilityFragment>\n            </WizardStep>\n          ))}\n        </Wizard>\n      </UtilityFragment>\n      <ExitDialog\n        exitDialogId={exitDialogId}\n        exitDialogRef={exitDialogRef as RefObject<HTMLDialogElement>}\n        onKeyNavigation={onKeyNavigation}\n      />\n    </nav>\n  );\n};\n"
          },
          "name": "Default single-page wizard"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Custom wizards",
          "url": {
            "iframe": "patterns/wizard/responsive-horizontal-wizard",
            "github": "apps/workshop/src/examples/patterns/wizard/responsive-horizontal-wizard.tsx"
          },
          "tags": [
            "patterns"
          ],
          "snippets": {
            "patterns/wizard/responsive-horizontal-wizard.tsx": "import {\n  MessageIcon,\n  VisaArrowBackTiny,\n  VisaArrowForwardTiny,\n  VisaCheckmarkTiny,\n  VisaChevronRightTiny,\n  VisaCloseTiny,\n  VisaErrorAltTiny,\n  VisaErrorTiny,\n} from '@visa/nova-icons-react';\nimport {\n  Badge,\n  Button,\n  ContentCard,\n  Input,\n  InputContainer,\n  InputMessage,\n  Label,\n  SectionMessage,\n  SectionMessageCloseButton,\n  SectionMessageContent,\n  Typography,\n  Utility,\n  UtilityFragment,\n  Wizard,\n  WizardStep,\n  useFocusTrap,\n  useWizard,\n} from '@visa/nova-react';\nimport { useEffect, useRef, useState, type CSSProperties, type ChangeEvent, type RefObject } from 'react';\nimport { SaveFlag } from './shared/save-flag';\nimport { SuccessMessage } from './shared/success-message';\nimport { SummaryPage } from './shared/summary-page';\nimport { ExitDialog } from './shared/exit-dialog';\n\n// Unique ID for wizard elements. Customize this or use React.useId() for dynamic generation.\nconst id = 'responsive-horizontal-wizard';\nconst navRegionAriaLabel = 'Responsive horizontal wizard';\n\n/**\n * Step configuration defining wizard structure.\n * Each step requires: label (badge text), title, inputLabel, inputId, and buttonId.\n * The final step (without inputId) is reserved for the summary page.\n */\nconst steps = [\n  {\n    label: '1',\n    title: 'Step 1 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-1-input`,\n    buttonId: `${id}-step-1-button`,\n  },\n  {\n    label: '2',\n    title: 'Step 2 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-2-input`,\n    buttonId: `${id}-step-2-button`,\n  },\n  {\n    label: '3',\n    title: 'Step 3 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-3-input`,\n    buttonId: `${id}-step-3-button`,\n  },\n  {\n    label: '4',\n    title: 'Step 4 label',\n    inputLabel: 'Label',\n    inputId: `${id}-step-4-input`,\n    buttonId: `${id}-step-4-button`,\n  },\n  {\n    label: '5',\n    title: 'Step 5 label',\n  },\n];\n\nconst exitDialogId = `${id}-exit-warning-dialog`;\n\nconst DEFAULT_INPUT_VALUES = Array(steps.length).fill('');\n\n/**\n * Multi-step form with responsive horizontal layout, validation, auto-save, and summary review.\n */\nexport const ResponsiveHorizontalWizard = () => {\n  const {\n    currentStep,\n    isStepAvailable,\n    isLastStep,\n    isStepComplete,\n    isStepError,\n    onStepError,\n    onStepChange,\n    onStepComplete,\n    onStepPrevious,\n    onWizardReset,\n  } = useWizard({ length: steps.length });\n\n  // Tracks step changes to trigger focus management in useEffect\n  const [hasWizardStepChanged, setHasWizardStepChanged] = useState(false);\n\n  const { onKeyNavigation, ref: exitDialogRef } = useFocusTrap();\n\n  const [inputValues, setInputValues] = useState(DEFAULT_INPUT_VALUES);\n\n  const [showSavedFlag, setShowSavedFlag] = useState(false);\n  const [formSubmitted, setFormSubmitted] = useState(false);\n  const [visibleErrorMessages, setVisibleErrorMessages] = useState<boolean[]>(Array(steps.length).fill(true));\n\n  // Ref maps for programmatic focus management when navigating or encountering errors\n  const inputRefs = useRef(new Map());\n  function getInputRefMap() {\n    if (!inputRefs.current) {\n      inputRefs.current = new Map();\n    }\n    return inputRefs.current;\n  }\n\n  const buttonRefs = useRef(new Map());\n  function getButtonRefMap() {\n    if (!buttonRefs.current) {\n      buttonRefs.current = new Map();\n    }\n    return buttonRefs.current;\n  }\n\n  const editButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n  // Manages focus after step changes for improved keyboard navigation\n  useEffect(() => {\n    if (!hasWizardStepChanged) {\n      return;\n    }\n    // apply focus to the input field of the current step\n    const inputRefsMap = getInputRefMap();\n    const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n    if (currentStepInputNode) {\n      currentStepInputNode.focus();\n    } else {\n      // focus the first available edit button in the array\n      const firstEditButton = editButtonRefs.current.find(ref => ref !== null);\n      if (firstEditButton) {\n        firstEditButton.focus();\n      }\n    }\n\n    setHasWizardStepChanged(false);\n  }, [hasWizardStepChanged, currentStep]);\n\n  /**\n   * Updates form data for a specific step.\n   *\n   * @param index - Step index to update\n   * @param event - Input change event containing new value\n   */\n  const handleInputChange = (index: number, event: ChangeEvent<HTMLInputElement>) => {\n    const value = event.target.value;\n    const newInputValues = [...inputValues];\n    newInputValues[index] = value;\n    setInputValues(newInputValues);\n  };\n\n  /**\n   * Validates current step and advances to next.\n   * Shows error if validation fails.\n   */\n  const handleClickNext = () => {\n    if (!inputValues[currentStep]) {\n      onStepError(currentStep);\n      // Reset error message visibility for this step\n      const newVisibleErrorMessages = [...visibleErrorMessages];\n      newVisibleErrorMessages[currentStep] = true;\n      setVisibleErrorMessages(newVisibleErrorMessages);\n      // find the input element with the error in the refs map and set focus on it\n      const inputRefsMap = getInputRefMap();\n      const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n      currentStepInputNode.focus();\n      return;\n    }\n\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepComplete(currentStep);\n  };\n\n  /**\n   * Returns to previous step without validation.\n   */\n  const handleClickPrevious = () => {\n    setHasWizardStepChanged(true);\n    setShowSavedFlag(false);\n    onStepPrevious();\n  };\n\n  /**\n   * Displays save confirmation flag.\n   */\n  const handleSave = () => {\n    setShowSavedFlag(true);\n  };\n\n  /**\n   * Resets wizard to initial state.\n   */\n  const handleResetWizard = () => {\n    setHasWizardStepChanged(true);\n    setInputValues(DEFAULT_INPUT_VALUES);\n    setFormSubmitted(false);\n    onWizardReset();\n  };\n\n  /**\n   * Collects form data and marks wizard as submitted.\n   */\n  const handleSubmit = () => {\n    const formValues: { [key: string]: string } = {};\n    steps.forEach((step, i) => {\n      if (!step.inputId) return;\n      formValues[step.inputId] = inputValues[i];\n    });\n    setFormSubmitted(true);\n  };\n\n  /**\n   * Opens exit confirmation dialog.\n   */\n  const handleExit = () => {\n    exitDialogRef.current?.showModal();\n  };\n\n  /**\n   * Hides error section message for a specific step.\n   *\n   * @param stepIndex - Index of the step whose error message should be hidden\n   */\n  const handleErrorMessageClose = (stepIndex: number) => {\n    const newVisibleErrorMessages = [...visibleErrorMessages];\n    newVisibleErrorMessages[stepIndex] = false;\n    setVisibleErrorMessages(newVisibleErrorMessages);\n  };\n\n  /**\n   * Handles direct navigation to a step from the wizard nav or summary page.\n   * Validates current step when navigating forward.\n   *\n   * @param i - Target step index\n   */\n  const handleClickStep = (i: number) => {\n    setHasWizardStepChanged(true);\n\n    // If navigating forward, validate current step like \"Next\"\n    if (i > currentStep) {\n      if (!inputValues[currentStep]) {\n        onStepError(currentStep);\n        const newVisibleErrorMessages = [...visibleErrorMessages];\n        newVisibleErrorMessages[currentStep] = true;\n        setVisibleErrorMessages(newVisibleErrorMessages);\n        // focus input with error\n        const inputRefsMap = getInputRefMap();\n        const currentStepInputNode = inputRefsMap.get(steps[currentStep].inputId);\n        if (currentStepInputNode) {\n          currentStepInputNode.focus();\n        }\n        return;\n      }\n      onStepComplete(currentStep);\n      onStepChange(i);\n    } else {\n      onStepChange(i);\n    }\n  };\n\n  /**\n   * Renders the final summary page with review and edit capabilities.\n   */\n  const renderSummaryStep = () => (\n    <SummaryPage\n      steps={steps}\n      inputValues={inputValues}\n      onStepClick={handleClickStep}\n      renderActionButtons={renderActionButtons}\n      maxWidth=\"603px\"\n      editButtonRefs={editButtonRefs.current}\n    />\n  );\n\n  /**\n   * Renders wizard action buttons with responsive layouts.\n   * Desktop: Horizontal layout with buttons grouped left/right.\n   * Mobile: Vertical stacked layout with full-width buttons.\n   */\n  const renderActionButtons = () => {\n    return (\n      <>\n        <Utility vContainerHide=\"xs\" vMarginTop={40}>\n          <Utility vJustifyContent=\"between\" vFlex vFlexWrap vGap={24}>\n            <Utility vJustifyContent=\"start\" vFlex vFlexWrap vColGap={24} vRowGap={16}>\n              <Button onClick={handleSave} colorScheme=\"secondary\">\n                Save\n              </Button>\n              <Button onClick={handleExit} colorScheme=\"tertiary\">\n                Exit\n              </Button>\n            </Utility>\n            <Utility vJustifyContent=\"end\" vFlex vFlexWrap vGap={24}>\n              <UtilityFragment vHide={currentStep === 0}>\n                <Button onClick={handleClickPrevious} colorScheme=\"secondary\">\n                  <VisaArrowBackTiny />\n                  Back\n                </Button>\n              </UtilityFragment>\n              <UtilityFragment vHide={currentStep === steps.length - 1}>\n                <Button onClick={handleClickNext}>\n                  Next\n                  <VisaArrowForwardTiny />\n                </Button>\n              </UtilityFragment>\n              <UtilityFragment vHide={currentStep !== steps.length - 1}>\n                <Button onClick={handleSubmit}>Submit</Button>\n              </UtilityFragment>\n            </Utility>\n          </Utility>\n        </Utility>\n        <UtilityFragment vContainerHide=\"desktop\">\n          <Utility vFlex vFlexCol vGap={16} vContainerHide=\"sm\" vMarginTop={40}>\n            <Button onClick={handleSave} colorScheme=\"secondary\">\n              Save\n            </Button>\n            <Button onClick={handleExit} colorScheme=\"tertiary\">\n              Exit\n            </Button>\n            <UtilityFragment vHide={currentStep === 0}>\n              <Button onClick={handleClickPrevious} colorScheme=\"secondary\">\n                <VisaArrowBackTiny />\n                Back\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep === steps.length - 1}>\n              <Button onClick={handleClickNext}>\n                Next\n                <VisaArrowForwardTiny />\n              </Button>\n            </UtilityFragment>\n            <UtilityFragment vHide={currentStep !== steps.length - 1}>\n              <Button onClick={handleSubmit}>Submit</Button>\n            </UtilityFragment>\n          </Utility>\n        </UtilityFragment>\n      </>\n    );\n  };\n\n  if (formSubmitted) {\n    return <SuccessMessage onReset={handleResetWizard} />;\n  }\n\n  /**\n   * Renders full horizontal wizard with step labels and titles for larger screens.\n   */\n  const renderDesktopWizard = () => {\n    return (\n      <nav aria-label={`${navRegionAriaLabel}-desktop`} style={{ inlineSize: '100%' }}>\n        <UtilityFragment vJustifyContent=\"center\">\n          <Wizard>\n            {steps.map((step, i) => (\n              <WizardStep key={`horizontal-wizard-step-${i + 1}`} aria-current={currentStep === i ? 'step' : undefined}>\n                {isStepAvailable(i) ? (\n                  <>\n                    <Button\n                      className={`${\n                        currentStep === i\n                          ? 'v-typography-label-large-active v-typography-color-default'\n                          : 'v-typography-label-large'\n                      }`}\n                      colorScheme=\"tertiary\"\n                      aria-label={`${isStepError(i) ? 'Error ' : isStepComplete(i) ? 'Completed ' : `${i + 1} `}${\n                        step.title\n                      }`}\n                      onClick={() => handleClickStep(i)}\n                      id={step.buttonId}\n                      ref={node => {\n                        const map = getButtonRefMap();\n                        if (node) {\n                          // store the node in the inputRefs Map\n                          map.set(step.buttonId, node);\n                        } else {\n                          map.delete(step.buttonId);\n                        }\n                      }}\n                    >\n                      <Utility vFlex vGap={8}>\n                        <Badge\n                          aria-current={i === currentStep ? 'step' : undefined}\n                          active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                          badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                          badgeVariant=\"icon\"\n                          clear={i !== currentStep}\n                          tag=\"span\"\n                        >\n                          {isStepError(i) ? (\n                            <VisaErrorAltTiny />\n                          ) : isStepComplete(i) ? (\n                            <VisaCheckmarkTiny />\n                          ) : (\n                            step.label\n                          )}\n                        </Badge>\n                        <Typography tag=\"span\">{step.title}</Typography>\n                      </Utility>\n                      {i < steps.length - 1 && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n                    </Button>\n                  </>\n                ) : (\n                  <>\n                    <Utility vFlex vGap={8}>\n                      <Badge\n                        active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                        clear={i !== currentStep}\n                        badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                        badgeVariant=\"icon\"\n                        tag=\"span\"\n                      >\n                        {isStepError(i) ? <VisaErrorAltTiny /> : isStepComplete(i) ? <VisaCheckmarkTiny /> : step.label}\n                      </Badge>\n                      <Typography variant={i === currentStep ? 'label-large-active' : 'label-large'}>\n                        {step.title}\n                      </Typography>\n                    </Utility>\n                    {!isLastStep(i) && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n                  </>\n                )}\n              </WizardStep>\n            ))}\n          </Wizard>\n        </UtilityFragment>\n      </nav>\n    );\n  };\n\n  /**\n   * Renders compact wizard showing only badge indicators for smaller screens.\n   */\n  const renderMobileWizard = () => {\n    return (\n      <nav aria-label={`${navRegionAriaLabel}-mobile`} style={{ inlineSize: '100%' }}>\n        <UtilityFragment vJustifyContent=\"center\">\n          <Wizard compact>\n            {steps.map((step, i) => (\n              <WizardStep key={`horizontal-wizard-step-${i + 1}`} aria-current={currentStep === i ? 'step' : undefined}>\n                <Badge\n                  aria-current={i === currentStep ? 'step' : undefined}\n                  active={i === currentStep && !isStepError(i) && !isStepComplete(i)}\n                  badgeType={isStepError(i) ? 'critical' : isStepComplete(i) ? 'stable' : 'subtle'}\n                  badgeVariant=\"icon\"\n                  clear={i !== currentStep}\n                  tag=\"span\"\n                >\n                  {isStepError(i) ? <VisaErrorAltTiny /> : isStepComplete(i) ? <VisaCheckmarkTiny /> : step.label}\n                </Badge>\n              </WizardStep>\n            ))}\n          </Wizard>\n        </UtilityFragment>\n      </nav>\n    );\n  };\n\n  return (\n    <Utility vFlex vFlexCol vGap={40} vAlignItems=\"center\" style={{ containerType: 'inline-size' } as CSSProperties}>\n      <SaveFlag show={showSavedFlag} onClose={() => setShowSavedFlag(false)} />\n      <UtilityFragment vContainerHide=\"mobile\">{renderDesktopWizard()}</UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\">{renderMobileWizard()}</UtilityFragment>\n      <Utility style={{ maxInlineSize: '603px', inlineSize: '100%' }}>\n        {steps.slice(0, steps.length - 1).map((step, i) => {\n          return (\n            <Utility key={i} vHide={currentStep !== i}>\n              <UtilityFragment vFlex vFlexCol vGap={24} vPadding={48}>\n                <ContentCard style={{ boxShadow: 'none' }}>\n                  <Utility vFlex vFlexCol vGap={isStepError(i) ? 16 : 8}>\n                    <Typography variant=\"headline-2\">{step.title}</Typography>\n                    {isStepError(i) && visibleErrorMessages[i] && (\n                      <SectionMessage messageType=\"error\" id=\"step-error-compact\">\n                        <MessageIcon messageType=\"error\" />\n                        <UtilityFragment vPaddingLeft={2} vPaddingBottom={2}>\n                          <SectionMessageContent>\n                            <Typography>\n                              One or more required fields are missing. Complete all required fields to continue.\n                            </Typography>\n                          </SectionMessageContent>\n                        </UtilityFragment>\n                        <SectionMessageCloseButton onClick={() => handleErrorMessageClose(i)}>\n                          <VisaCloseTiny />\n                        </SectionMessageCloseButton>\n                      </SectionMessage>\n                    )}\n                    <Typography variant=\"body-1\">* Indicates a required field.</Typography>\n                  </Utility>\n                  <Utility vFlex vFlexCol vGap={4}>\n                    <Label htmlFor={step.inputId}>{`* ${step.inputLabel}`}</Label>\n                    <InputContainer>\n                      <Input\n                        aria-describedby={isStepError(i) ? `step-error-compact ${step.inputId}-message` : undefined}\n                        aria-required=\"true\"\n                        aria-invalid={isStepError(i)}\n                        id={step.inputId}\n                        type=\"text\"\n                        value={inputValues[i]}\n                        onChange={e => handleInputChange(i, e as ChangeEvent<HTMLInputElement>)}\n                        ref={node => {\n                          const map = getInputRefMap();\n                          if (node) {\n                            // store the node in the inputRefs Map\n                            map.set(step.inputId, node);\n                          } else {\n                            map.delete(step.inputId);\n                          }\n                        }}\n                      />\n                    </InputContainer>\n                    {isStepError(i) && (\n                      <InputMessage id={`${step.inputId}-message`}>\n                        <VisaErrorTiny />\n                        This is a required field.\n                      </InputMessage>\n                    )}\n                  </Utility>\n                </ContentCard>\n              </UtilityFragment>\n              <UtilityFragment vMarginTop={10}>\n                <Typography variant=\"body-3\">Changes have been automatically saved.</Typography>\n              </UtilityFragment>\n              {renderActionButtons()}\n            </Utility>\n          );\n        })}\n        {currentStep === steps.length - 1 && renderSummaryStep()}\n      </Utility>\n      <ExitDialog\n        exitDialogId={exitDialogId}\n        exitDialogRef={exitDialogRef as RefObject<HTMLDialogElement>}\n        onKeyNavigation={onKeyNavigation}\n      />\n    </Utility>\n  );\n};\n"
          },
          "name": "Responsive horizontal wizard"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/wizard/exit-dialog.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/wizard/shared/exit-dialog.tsx": "import { Button, Dialog, DialogCloseButton, DialogContent, DialogHeader, Typography, Utility } from '@visa/nova-react';\nimport { VisaCloseTiny, MessageIcon } from '@visa/nova-icons-react';\nimport type { RefObject } from 'react';\n\n/**\n * @property exitDialogId - Unique ID for dialog accessibility attributes\n * @property exitDialogRef - Dialog ref for programmatic control (open/close)\n * @property onKeyNavigation - Keyboard handler that constrains focus within the dialog while open\n */\ninterface ExitDialogProps {\n  exitDialogId: string;\n  exitDialogRef: RefObject<HTMLDialogElement>;\n  onKeyNavigation: (e: React.KeyboardEvent<HTMLDialogElement>, isOpen?: boolean) => void;\n}\n\n/**\n * Warning dialog shown when user attempts to exit the wizard.\n */\nexport const ExitDialog = ({ exitDialogId, exitDialogRef, onKeyNavigation }: ExitDialogProps) => {\n  return (\n    <Dialog\n      aria-describedby={`${exitDialogId}-description`}\n      aria-labelledby={`${exitDialogId}-title`}\n      ref={exitDialogRef}\n      id={exitDialogId}\n      messageType=\"warning\"\n      onKeyDown={e => onKeyNavigation(e, exitDialogRef.current?.open)}\n      style={{ maxWidth: '300px' }}\n    >\n      <DialogContent>\n        <DialogHeader id={`${exitDialogId}-title`}>\n          <MessageIcon messageType=\"warning\" />\n          Exit form?\n        </DialogHeader>\n        <Typography id={`${exitDialogId}-description`}>\n          Your progress has been automatically saved. You can continue where you left off when you return.\n        </Typography>\n        <Utility vFlex vFlexWrap vGap={8} vPaddingTop={16}>\n          <Button\n            style={{ width: '100%' }}\n            onClick={() => {\n              window?.location?.reload();\n            }}\n          >\n            Exit\n          </Button>\n        </Utility>\n      </DialogContent>\n      <DialogCloseButton onClick={() => exitDialogRef.current?.close()}>\n        <VisaCloseTiny />\n      </DialogCloseButton>\n    </Dialog>\n  );\n};\n"
          },
          "name": "Exit dialog"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/wizard/save-flag.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/wizard/shared/save-flag.tsx": "import { Flag, FlagCloseButton, FlagContent, ScreenReader, UtilityFragment } from '@visa/nova-react';\nimport { VisaCloseTiny, MessageIcon } from '@visa/nova-icons-react';\n\n/**\n * @property show - Controls flag visibility\n * @property onClose - Callback when user closes the flag\n */\ninterface SaveFlagProps {\n  show: boolean;\n  onClose: () => void;\n}\n\n/**\n * Success flag notification shown when user saves wizard progress.\n */\nexport const SaveFlag = ({ show, onClose }: SaveFlagProps) => {\n  if (!show) return null;\n\n  return (\n    <UtilityFragment vAlignSelf=\"end\">\n      <Flag messageType=\"success\">\n        <MessageIcon messageType=\"success\" />\n        <FlagContent className=\"v-pl-2 v-pb-2\" role=\"alert\" aria-live=\"polite\">\n          <ScreenReader>success</ScreenReader>\n          Your progress has been saved.\n        </FlagContent>\n        <FlagCloseButton onClick={onClose}>\n          <VisaCloseTiny />\n        </FlagCloseButton>\n      </Flag>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Save flag"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/wizard/success-message.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/wizard/shared/success-message.tsx": "import { Link, Surface, Typography, Utility, UtilityFragment } from '@visa/nova-react';\nimport { VisaSuccessHigh } from '@visa/nova-icons-react';\nimport type { CSSProperties } from 'react';\n\n/**\n * @property onReset - Callback invoked when user resets the wizard\n */\ninterface SuccessMessageProps {\n  onReset: () => void;\n}\n\n/**\n * Success confirmation page shown after wizard submission.\n */\nexport const SuccessMessage = ({ onReset }: SuccessMessageProps) => {\n  return (\n    <Utility vFlex vJustifyContent=\"center\" vGap={12}>\n      <UtilityFragment\n        vFlex\n        vJustifyContent=\"center\"\n        vPaddingVertical={44}\n        vPaddingHorizontal={32}\n        vGap={32}\n        style={{ maxWidth: '676px' }}\n      >\n        <Surface>\n          <Utility\n            vFlex\n            vFlexCol\n            vGap={24}\n            vAlignItems=\"center\"\n            style={{ maxWidth: '394px', width: '394px' }}\n            role=\"alert\"\n            aria-live=\"polite\"\n          >\n            <Typography tag=\"h2\" variant=\"headline-2\">\n              Success\n            </Typography>\n            <VisaSuccessHigh\n              style={\n                {\n                  '--v-icon-primary': 'var(--palette-messaging-graphics-positive)',\n                  '--v-icon-secondary': 'var(--palette-messaging-graphics-positive)',\n                } as CSSProperties\n              }\n            />\n            <Typography tag=\"p\" variant=\"body-2\">\n              This is required text that describes the success message in more detail.\n            </Typography>\n            <Utility vAlignSelf=\"stretch\" vFlex vJustifyContent=\"center\" vGap={24}>\n              <Link element={<button />} onClick={onReset}>\n                Reset Wizard example\n              </Link>\n              <Link href=\"./wizard\">Destination label</Link>\n            </Utility>\n          </Utility>\n        </Surface>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Success message"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Shared Components",
          "url": {
            "iframe": "",
            "github": "apps/workshop/src/examples/patterns/wizard/summary-page.tsx"
          },
          "tags": [
            "patterns",
            "isShared"
          ],
          "snippets": {
            "patterns/wizard/shared/summary-page.tsx": "import { Button, ContentCard, Surface, Typography, Utility, UtilityFragment, type VSpacing } from '@visa/nova-react';\nimport { VisaEditTiny } from '@visa/nova-icons-react';\nimport type { JSX } from 'react';\n\n/**\n * Step configuration object\n *\n * @property label - Step label text\n * @property title - Step title displayed in summary\n * @property inputLabel - (optional) Label for input field\n * @property inputId - (optional) ID for input element\n * @property buttonId - (optional) ID for button element\n */\ninterface Step {\n  label: string;\n  title: string;\n  inputLabel?: string;\n  inputId?: string;\n  buttonId?: string;\n}\n\n/**\n * Props for the SummaryPage component\n *\n * Supports two rendering modes:\n * 1. Standalone page with ContentCard wrapper and action buttons\n * 2. Inline summary with Surface wrapper for single-page wizard\n *\n * @property steps - Array of step configuration objects\n * @property inputValues - Input values corresponding to each step\n * @property onStepClick - Callback when edit button clicked, receives step index\n * @property renderActionButtons - (optional) Render function for action buttons in standalone mode\n * @property vPaddingHorizontal - (optional) Horizontal padding for inline mode\n * @property maxWidth - (optional) Max width for standalone mode\n * @property surfaceProps - (optional) Additional props for Surface wrapper in inline mode\n * @property containerProps - (optional) Additional props for container Utility in inline mode\n * @property editButtonRefs - (optional) Refs array for edit buttons to manage focus\n */\ninterface SummaryPageProps {\n  steps: Step[];\n  inputValues: string[];\n  onStepClick: (index: number) => void;\n  renderActionButtons?: () => JSX.Element;\n  vPaddingHorizontal?: VSpacing;\n  maxWidth?: string;\n  surfaceProps?: React.ComponentProps<typeof Surface>;\n  containerProps?: React.ComponentProps<typeof Utility>;\n  editButtonRefs?: (HTMLButtonElement | null)[];\n}\n\n/**\n * Renders summary of wizard steps with edit capabilities.\n * Adapts layout based on whether it's used standalone or inline.\n */\nexport const SummaryPage = ({\n  steps,\n  inputValues,\n  onStepClick,\n  renderActionButtons,\n  vPaddingHorizontal,\n  maxWidth,\n  surfaceProps = {},\n  containerProps = {},\n  editButtonRefs = [],\n}: SummaryPageProps) => {\n  // Exclude the summary step itself (last step) from the list\n  const summarySteps = steps.slice(0, steps.length - 1);\n\n  // Core summary content rendered in both modes\n  const renderSummaryContent = () => (\n    <>\n      <Typography tag=\"h2\" variant=\"headline-2\">\n        Summary\n      </Typography>\n      <ol>\n        {summarySteps.map((step, i) => (\n          <UtilityFragment\n            key={i}\n            vPaddingVertical={20}\n            style={{\n              borderBlockEnd: i < summarySteps.length - 1 ? '1px solid rgba(0,0,0,0.10)' : 'none',\n              paddingBlockEnd: i < summarySteps.length - 1 ? '20px' : '0',\n            }}\n          >\n            <li>\n              <Utility vFlex vJustifyContent=\"between\">\n                <Typography tag=\"h3\" variant=\"body-2-bold\" colorScheme=\"subtle\">\n                  {`${i + 1}. ${step.title}`}\n                </Typography>\n                <Button\n                  aria-label={`Edit step ${i + 1}`}\n                  colorScheme=\"tertiary\"\n                  iconButton\n                  buttonSize=\"small\"\n                  onClick={() => onStepClick(i)}\n                  ref={node => {\n                    editButtonRefs[i] = node;\n                  }}\n                >\n                  <VisaEditTiny rtl />\n                </Button>\n              </Utility>\n              <Typography>{`${step.inputLabel}: ${inputValues[i]}`}</Typography>\n            </li>\n          </UtilityFragment>\n        ))}\n      </ol>\n    </>\n  );\n\n  // For inline summary (like in single-page wizard)\n  if (vPaddingHorizontal) {\n    return (\n      <UtilityFragment vPaddingHorizontal={vPaddingHorizontal}>\n        <Surface {...surfaceProps}>\n          <Utility vFlexGrow {...containerProps}>\n            {renderSummaryContent()}\n          </Utility>\n        </Surface>\n      </UtilityFragment>\n    );\n  }\n\n  // For standalone summary page\n  return (\n    <Utility vAlignSelf=\"center\" vFlex vFlexCol vGap={10} style={{ maxWidth: maxWidth, width: '100%' }}>\n      <UtilityFragment vAlignSelf=\"center\" vFlex vJustifyContent=\"center\" vPadding={48} vGap={32}>\n        <ContentCard style={{ boxShadow: 'none', inlineSize: '100%' }}>\n          <Utility style={{ inlineSize: '100%' }}>{renderSummaryContent()}</Utility>\n        </ContentCard>\n      </UtilityFragment>\n      <Typography variant=\"body-3\">Changes have been automatically saved.</Typography>\n      {renderActionButtons && renderActionButtons()}\n    </Utility>\n  );\n};\n"
          },
          "name": "Summary page"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Wizardstep",
          "selector": "<WizardStep />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Represents an individual step within a multi-step wizard process."
        },
        {
          "order": 2,
          "name": "Badge",
          "selector": "<Badge />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Visual indicators communicating the status of a component."
        },
        {
          "order": 3,
          "name": "Button",
          "selector": "<Button />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Interactive elements enabling users to take actions within an interface."
        },
        {
          "order": 4,
          "name": "useWizard",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to control the state of a wizard component."
        },
        {
          "order": 5,
          "name": "useAccordion",
          "selector": null,
          "libraryId": null,
          "componentId": null,
          "type": "hooks",
          "description": "This hook is used to manage the open state and keyboard navigation of accordions."
        },
        {
          "order": 6,
          "name": "badge",
          "type": "related",
          "selector": "<Badge />",
          "description": ""
        },
        {
          "order": 7,
          "name": "button",
          "type": "related",
          "selector": "<Button />",
          "description": ""
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Wizardstep",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Wizardstep",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "li",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "active",
          "section": "Badge",
          "data": {
            "name": "active",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Active style"
          }
        },
        {
          "name": "badgeType",
          "section": "Badge",
          "data": {
            "name": "badgeType",
            "type": "\"subtle\" , \"critical\" , \"neutral\" , \"stable\" , \"warning\"",
            "default": "",
            "required": "false",
            "description": "Type of Badge"
          }
        },
        {
          "name": "badgeVariant",
          "section": "Badge",
          "data": {
            "name": "badgeVariant",
            "type": "\"number\" , \"icon\"",
            "default": "",
            "required": "false",
            "description": "Variant of Badge"
          }
        },
        {
          "name": "clear",
          "section": "Badge",
          "data": {
            "name": "clear",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Clear background"
          }
        },
        {
          "name": "tag",
          "section": "Badge",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag of Component"
          }
        },
        {
          "name": "alternate",
          "section": "Button",
          "data": {
            "name": "alternate",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Alternate color scheme"
          }
        },
        {
          "name": "buttonSize",
          "section": "Button",
          "data": {
            "name": "buttonSize",
            "type": "\"small\" , \"large\" , \"medium\"",
            "default": "",
            "required": "false",
            "description": "Size of Button"
          }
        },
        {
          "name": "colorScheme",
          "section": "Button",
          "data": {
            "name": "colorScheme",
            "type": "\"primary\" , \"secondary\" , \"tertiary\"",
            "default": "",
            "required": "false",
            "description": "Color Scheme of Button"
          }
        },
        {
          "name": "destructive",
          "section": "Button",
          "data": {
            "name": "destructive",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Destructive Button"
          }
        },
        {
          "name": "element",
          "section": "Button",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "iconButton",
          "section": "Button",
          "data": {
            "name": "iconButton",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Button"
          }
        },
        {
          "name": "iconTwoColor",
          "section": "Button",
          "data": {
            "name": "iconTwoColor",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Icon Two Button"
          }
        },
        {
          "name": "stacked",
          "section": "Button",
          "data": {
            "name": "stacked",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Stacked Button"
          }
        },
        {
          "name": "subtle",
          "section": "Button",
          "data": {
            "name": "subtle",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": "Subtle Button"
          }
        },
        {
          "name": "tag",
          "section": "Button",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "button",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        }
      ]
    },
    {
      "name": "use-accordion",
      "version": "0.0.1",
      "description": "This hook is used to manage the open state and keyboard navigation of accordions.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-accordion/use-accordion-example",
            "github": "apps/workshop/src/examples/hooks/use-accordion/use-accordion-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny, VisaChevronRightTiny } from '@visa/nova-icons-react';\nimport {\n  Accordion,\n  AccordionHeading,\n  AccordionPanel,\n  AccordionToggleIcon,\n  Typography,\n  useAccordion,\n} from '@visa/nova-react';\nimport { Fragment } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'use-accordion-usage';\n\nconst accordions = [\n  {\n    content: 'This is required text that describes the accordion section in more detail.',\n    header: 'Section label 1',\n  },\n];\n\nexport const UseAccordionExample = () => {\n  // useAccordion hook returns the following:\n  // isIndexExpanded: function that returns a boolean value to determine if the accordion is expanded or not\n  // onKeyNavigation: function that handles keyboard navigation, and toggles the accordion expanded state\n  // ref: a ref object that is used to store the accordion elements\n  // toggleIndexExpanded: function that toggles the accordion expanded state, based on the index provided\n  const { isIndexExpanded, onKeyNavigation, ref, toggleIndexExpanded } = useAccordion();\n\n  return (\n    <Accordion id={id} onKeyDown={onKeyNavigation} tag=\"div\">\n      {accordions.map((accordion, i) => (\n        <Fragment key={i}>\n          <AccordionHeading\n            aria-controls={`${id}-panel-${i}`}\n            aria-expanded={isIndexExpanded(i)}\n            buttonSize=\"large\"\n            colorScheme=\"secondary\"\n            id={`${id}-header-${i}`}\n            onClick={() => toggleIndexExpanded(i)}\n            ref={el => {\n              ref.current[i] = el;\n            }}\n            tag=\"button\"\n          >\n            <AccordionToggleIcon\n              accordionOpen={isIndexExpanded(i)}\n              elementClosed={<VisaChevronRightTiny rtl />}\n              elementOpen={<VisaChevronDownTiny />}\n            />\n            {accordion.header}\n          </AccordionHeading>\n          <AccordionPanel aria-hidden={!isIndexExpanded(i)} id={`${id}-panel-${i}`}>\n            <Typography tag=\"span\">{accordion.content}</Typography>\n          </AccordionPanel>\n        </Fragment>\n      ))}\n    </Accordion>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "defaultExpanded",
          "data": {
            "order": 1,
            "name": "defaultExpanded",
            "type": "string , number , (string , number)[]",
            "default": "",
            "required": "",
            "description": "Default expanded state of the accordion"
          }
        },
        {
          "section": "Properties",
          "name": "ref",
          "data": {
            "order": 2,
            "name": "ref",
            "type": "RefObject",
            "default": "",
            "required": "",
            "description": "Ref for the accordion elements"
          }
        },
        {
          "section": "Returns",
          "name": "isIndexExpanded",
          "data": {
            "order": 1,
            "name": "isIndexExpanded",
            "type": "(index: number , string) => boolean",
            "description": "Function that takes in index or id of element and returns expanded boolean"
          }
        },
        {
          "section": "Returns",
          "name": "onKeyNavigation",
          "data": {
            "order": 2,
            "name": "onKeyNavigation",
            "type": "(e: KeyboardEvent) => void",
            "description": "Function that handles on key down for navigation"
          }
        },
        {
          "section": "Returns",
          "name": "ref",
          "data": {
            "order": 3,
            "name": "ref",
            "type": "MutableRefObject",
            "description": "Ref object to use if ref isn't supplied in props"
          }
        },
        {
          "section": "Returns",
          "name": "toggleIndexExpanded",
          "data": {
            "order": 4,
            "name": "toggleIndexExpanded",
            "type": "(index: number , string) => void",
            "description": "Callback to toggle accordion expanded state"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-card-number-validation",
      "version": "0.0.1",
      "description": "Removes all non-numeric characters",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-card-number-validation/use-card-validation-example",
            "github": "apps/workshop/src/examples/hooks/use-card-number-validation/use-card-validation-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaChevronDownTiny } from '@visa/nova-icons-react';\nimport {\n  Divider,\n  Input,\n  InputContainer,\n  InputControl,\n  Label,\n  Select,\n  Switch,\n  SwitchLabel,\n  useCardNumberValidation,\n  Typography,\n  Utility,\n} from '@visa/nova-react';\nimport { useState } from 'react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'use-card-validation-example';\n\nexport const UseCardValidationUsage = () => {\n  /// These states are for demo purposes:\n  const [cardNumberInputValueKey, setCardNumberInputValueKey] = useState('cardNumberInputValue');\n  const [trimToMaxLength, setTrimToMaxLength] = useState(true);\n\n  const {\n    binValid,\n    brand,\n    brandValid,\n    cardNumberInputValue,\n    cardNumberValidator,\n    cleanCardNumber,\n    formattedCardNumber,\n    lastDigitValid,\n    lengthValid,\n    onCardNumberChange,\n    valid,\n  } = useCardNumberValidation({\n    allowedBrands: ['VISA'],\n    defaultCardNumberInputValue: '40000000 hello world 00000000 000000',\n    trimToMaxLength,\n  });\n\n  const valueMap: Record<string, string> = { cardNumberInputValue, cleanCardNumber, formattedCardNumber };\n  const valueMapKeys = Object.keys(valueMap);\n\n  return (\n    <Utility vFlexCol vGap={16}>\n      <Utility vFlex vFlexCol vGap={4}>\n        <Label htmlFor={`${id}-card-number-input`}>Visa card number</Label>\n        <InputContainer>\n          <Input\n            aria-required=\"true\"\n            autoComplete=\"cc-number\"\n            id={`${id}-card-number-input`}\n            onChange={event => onCardNumberChange(event.currentTarget.value)}\n            required\n            type=\"text\"\n            value={valueMap[cardNumberInputValueKey]}\n          />\n        </InputContainer>\n      </Utility>\n      <code>binValid: {binValid.toString()}</code>\n      <code>brand: {brand ?? 'undefined'}</code>\n      <code>brandValid: {brandValid.toString()}</code>\n      <code>cardNumberInputValue: {cardNumberInputValue}</code>\n      <code>cardNumberValidator.brand: {cardNumberValidator?.brand ?? 'undefined'}</code>\n      <code>cardNumberValidator.maxLength: {cardNumberValidator?.maxLength ?? 'undefined'}</code>\n      <code>cleanCardNumber: {cleanCardNumber}</code>\n      <code>formattedCardNumber: {formattedCardNumber}</code>\n      <code>lastDigitValid: {lastDigitValid.toString()}</code>\n      <code>lengthValid: {lengthValid.toString()}</code>\n      <code>valid: {valid.toString()}</code>\n\n      <Divider />\n\n      <Typography tag=\"span\" variant=\"body-2-bold\">\n        Demo options:\n      </Typography>\n      <Utility tag=\"fieldset\" vFlex vFlexCol vGap={6}>\n        <Label htmlFor={`${id}-input-value-key-select`}>Visa card number input value</Label>\n        <InputContainer>\n          <Select\n            id={`${id}-input-value-key-select`}\n            name=\"select-default-example\"\n            onChange={event => setCardNumberInputValueKey(event.currentTarget.value)}\n            value={cardNumberInputValueKey}\n          >\n            {valueMapKeys.map(key => (\n              <option key={key} value={key}>\n                {key}\n              </option>\n            ))}\n          </Select>\n          <InputControl>\n            <VisaChevronDownTiny />\n          </InputControl>\n        </InputContainer>\n      </Utility>\n      <Utility vFlex vFlexWrap vGap={10} vJustifyContent=\"between\" vMargin={8}>\n        <SwitchLabel htmlFor={`${id}-trim-value-switch`}>\n          <code>trimToMaxLength</code>\n        </SwitchLabel>\n        <Switch\n          checked={trimToMaxLength}\n          id={`${id}-trim-value-switch`}\n          name={`${id}-trim-value-switch`}\n          onChange={event => setTrimToMaxLength(event.currentTarget.checked)}\n        />\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        }
      ],
      "apiSectionValues": [
        {
          "section": "Returns",
          "name": "binValid",
          "data": {
            "order": 1,
            "name": "binValid",
            "type": "boolean",
            "description": "BIN is valid"
          }
        },
        {
          "section": "Returns",
          "name": "brand",
          "data": {
            "order": 2,
            "name": "brand",
            "type": "Brand , undefined",
            "description": "Brand if BIN is valid, undefined if BIN is not valid"
          }
        },
        {
          "section": "Returns",
          "name": "brandValid",
          "data": {
            "order": 3,
            "name": "brandValid",
            "type": "boolean",
            "description": "The brand input is included in allowedBrands"
          }
        },
        {
          "section": "Returns",
          "name": "cardNumberInputValue",
          "data": {
            "order": 4,
            "name": "cardNumberInputValue",
            "type": "string",
            "description": "Raw input value state sent from onCardNumberChange"
          }
        },
        {
          "section": "Returns",
          "name": "cardValidator",
          "data": {
            "order": 5,
            "name": "cardValidator",
            "type": "CardValidator",
            "description": "Card validator from BIN if BIN is matched, undefined if BIN not recognized"
          }
        },
        {
          "section": "Returns",
          "name": "cleanCardNumber",
          "data": {
            "order": 6,
            "name": "cleanCardNumber",
            "type": "string",
            "description": "cardNumberInputValue with non digit values filtered out, and/or max characters removed"
          }
        },
        {
          "section": "Returns",
          "name": "formattedCardNumber",
          "data": {
            "order": 7,
            "name": "formattedCardNumber",
            "type": "string",
            "description": "cleanCardNumber with the proper spacing"
          }
        },
        {
          "section": "Returns",
          "name": "lastDigitValid",
          "data": {
            "order": 8,
            "name": "lastDigitValid",
            "type": "boolean",
            "description": "Valid last digit based off mod 10 check"
          }
        },
        {
          "section": "Returns",
          "name": "lengthValid",
          "data": {
            "order": 9,
            "name": "lengthValid",
            "type": "boolean",
            "description": "The card number length is valid, validated with cleanCardNumber"
          }
        },
        {
          "section": "Returns",
          "name": "onCardNumberChange",
          "data": {
            "order": 10,
            "name": "onCardNumberChange",
            "type": "(cardNumberInputValue: string) => void",
            "description": "Setter for cardNumberInputValue state"
          }
        },
        {
          "section": "Returns",
          "name": "valid",
          "data": {
            "order": 11,
            "name": "valid",
            "type": "boolean",
            "description": "The card number is fully valid based on BIN regex's, allowed brands, length, and modulo 10 check"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ],
      "devNote": "This validator array is not comprehensive and is subject to change. VPDS does not maintain acceptance marks for all brands for legal reasons.",
      "disclaimer": "This hook's validation is not comprehensive and is subject to change. VPDS does not maintain acceptance marks for all brands for legal reasons. This hook is designed to let you bring your own validators, if custom validators are required for your use case."
    },
    {
      "name": "use-debounce",
      "version": "0.0.1",
      "description": "Debounces expensive function, only calling the function after it's last call has waited for specified delay",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-debounce/use-button-debounce-example",
            "github": "apps/workshop/src/examples/hooks/use-debounce/use-button-debounce-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Typography, Utility, useDebounce } from '@visa/nova-react';\nimport { VisaInformationTiny, VisaSuccessTiny } from \"@visa/nova-icons-react\";\nimport { useState, type CSSProperties } from 'react';\n\nexport const UseButtonDebounceExample = () => {\n  const [success, setSuccess] = useState(false);\n\n  const onDebouncedClick = useDebounce(() => {\n    setSuccess(true);\n  }, 1000);\n\n  return (\n    <Utility vFlex vFlexCol vGap={12}>\n      <Typography tag=\"span\" variant=\"body-2-bold\">\n        Rapidly click the button in sequence, then wait for one second:\n      </Typography>\n\n      <Utility vFlex vFlexRow vGap={12}>\n        <Button onClick={onDebouncedClick}>Submit debounced</Button>\n        <Button colorScheme=\"secondary\" onClick={() => setSuccess(false)}>\n          Reset\n        </Button>\n      </Utility>\n\n      <Typography aria-atomic=\"true\" aria-live=\"assertive\" style={{lineHeight: '16px'}}>\n        {success ? <VisaSuccessTiny style={{ '--v-icon-primary': 'green', '--v-icon-secondary': 'var(--v-message-text-success)', marginInlineEnd: '3px', verticalAlign: 'bottom' } as CSSProperties} /> : \n        <VisaInformationTiny style={{ '--v-icon-primary': 'var(--palette-default-text-subtle)', '--v-icon-secondary': 'var(--palette-default-text-subtle)', marginInlineEnd: '3px', verticalAlign: 'bottom' } as CSSProperties} />}\n        {success ? 'Button click successful, many thanks' : 'Waiting for button click'}\n      </Typography>\n    </Utility>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Arguments",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Arguments",
          "name": "callback",
          "data": {
            "order": 1,
            "name": "callback",
            "type": "(...args: any[]) => void",
            "default": "",
            "required": "yes",
            "description": "Function that runs after last delay"
          }
        },
        {
          "section": "Arguments",
          "name": "delay",
          "data": {
            "order": 2,
            "name": "delay",
            "type": "number",
            "default": 250,
            "required": "",
            "description": "Length of time to wait since last call was made (milliseconds)"
          }
        },
        {
          "section": "Returns",
          "data": "typeof callback"
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-focus-trap",
      "version": "0.0.1",
      "description": "This hook is used to trap focus inside a container.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-focus-trap/use-focus-trap-example",
            "github": "apps/workshop/src/examples/hooks/use-focus-trap/use-focus-trap-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaCloseTiny } from '@visa/nova-icons-react';\nimport {\n  Button,\n  Dialog,\n  DialogCloseButton,\n  DialogContent,\n  DialogHeader,\n  Typography,\n  useFocusTrap,\n  Utility,\n} from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'use-focus-trap-usage';\n\nexport const UseFocusTrapExample = () => {\n  const { onKeyNavigation, ref } = useFocusTrap();\n\n  return (\n    <>\n      <Button onClick={() => ref.current?.showModal()}>Open dialog</Button>\n      <Dialog\n        aria-describedby={`${id}-description`}\n        aria-labelledby={`${id}-title`}\n        id={id}\n        ref={ref}\n        onKeyDown={e => onKeyNavigation(e, ref.current?.open)}\n      >\n        <DialogContent>\n          <DialogHeader id={`${id}-title`}>Default title</DialogHeader>\n          <Typography id={`${id}-description`}>\n            This is required text that describes the dialog title in more detail.\n          </Typography>\n          <Utility vAlignItems=\"center\" vFlex vFlexWrap vGap={8} vJustifyContent=\"end\" vPaddingTop={16}>\n            <Button>Primary action</Button>\n            <Button colorScheme=\"secondary\">Secondary action</Button>\n          </Utility>\n        </DialogContent>\n        <DialogCloseButton onClick={() => ref.current?.close()}>\n          <VisaCloseTiny />\n        </DialogCloseButton>\n      </Dialog>\n    </>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "document",
          "data": {
            "order": 1,
            "name": "document",
            "type": "Document",
            "default": "",
            "required": "",
            "description": "Document object"
          }
        },
        {
          "section": "Properties",
          "name": "querySelector",
          "data": {
            "order": 2,
            "name": "querySelector",
            "type": "string",
            "default": "a[href], button:not(disabled), textarea:not(disabled), input:not(disabled), select:not(disabled)",
            "required": "",
            "description": "DOM elements selector"
          }
        },
        {
          "section": "Properties",
          "name": "ref",
          "data": {
            "order": 3,
            "name": "ref",
            "type": "RefObject",
            "default": "",
            "required": "",
            "description": "Ref object to use if ref isn't supplied in properties."
          }
        },
        {
          "section": "Returns",
          "name": "onKeyNavigation",
          "data": {
            "order": 1,
            "name": "onKeyNavigation",
            "type": "(e: KeyboardEvent, open?: boolean) => void",
            "description": "Function that handles on key down for navigation"
          }
        },
        {
          "section": "Returns",
          "name": "ref",
          "data": {
            "order": 2,
            "name": "ref",
            "type": "MutableRefObject",
            "description": "Ref object to use if ref isn't supplied in props"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-listbox",
      "version": "0.0.1",
      "description": "This hook is used to manage the selected state and keyboard navigation of listbox component.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-listbox/use-listbox-example",
            "github": "apps/workshop/src/examples/hooks/use-listbox/use-listbox-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Label, Listbox, ListboxContainer, ListboxItem, useListbox } from '@visa/nova-react';\n\n// TIP: Customize this ID, pass it as a prop, or auto-generate it with useId() from @react\nconst id = 'use-listbox-usage';\n\nconst options = [\n  {\n    label: 'Item A',\n  },\n  {\n    disabled: true,\n    label: 'Item B',\n  },\n  {\n    label: 'Item C',\n  },\n  {\n    label: 'Item D',\n  },\n  {\n    label: 'Item E',\n  },\n];\n\nexport const UseListboxExample = () => {\n  // useListbox hook returns the following:\n  // isIndexSelected: function that returns a boolean value to determine if the index is selected or not\n  // getTabIndex: function that returns the correct tabIndex based on the index and disabled state\n  // onKeyNavigation: function that handles keyboard navigation, and toggles the list item selected state\n  // ref: a ref object that is used to store the list item elements\n  // toggleIndexSelected: function that toggles the list item selected state, based on the index provided\n  const { isIndexSelected, getTabIndex, onKeyNavigation, ref, toggleIndexSelected } = useListbox({\n    defaultSelected: 0,\n  }); // Default to active on first list item\n\n  return (\n    <fieldset>\n      <Label id={`${id}-legend`} tag=\"legend\">\n        Label (required)\n      </Label>\n      <ListboxContainer>\n        <Listbox aria-labelledby={`${id}-legend`} id={id} onKeyDown={onKeyNavigation} role=\"listbox\" scroll>\n          {options.map((option, index) => (\n            <ListboxItem\n              aria-disabled={option.disabled}\n              aria-selected={isIndexSelected(index)}\n              key={`${id}-option-${index}`}\n              onClick={() => toggleIndexSelected(index)}\n              ref={el => {\n                ref.current[index] = el;\n              }}\n              role=\"option\"\n              tabIndex={getTabIndex(index, option.disabled)}\n            >\n              <span className=\"v-radio v-flex-shrink-0 \" />\n              {option.label}\n            </ListboxItem>\n          ))}\n        </Listbox>\n      </ListboxContainer>\n    </fieldset>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "autoSelect",
          "data": {
            "order": 1,
            "name": "autoSelect",
            "type": "boolean",
            "default": "",
            "required": "",
            "description": "Auto select (not compatible with multi-select listbox)"
          }
        },
        {
          "section": "Properties",
          "name": "defaultSelected",
          "data": {
            "order": 2,
            "name": "defaultSelected",
            "type": "number , number[]",
            "default": -1,
            "required": "",
            "description": "Default selected elements"
          }
        },
        {
          "section": "Properties",
          "name": "ref",
          "data": {
            "order": 3,
            "name": "ref",
            "type": "RefObject",
            "default": "",
            "required": "",
            "description": "Ref for the tab elements"
          }
        },
        {
          "section": "Returns",
          "name": "isIndexSelected",
          "data": {
            "order": 1,
            "name": "isIndexSelected",
            "type": "(index: number) => boolean",
            "description": "Function that returns true if index is selected"
          }
        },
        {
          "section": "Returns",
          "name": "getTabIndex",
          "data": {
            "order": 2,
            "name": "getTabIndex",
            "type": "(index: number, disabled?: boolean) => -1 , 0",
            "description": "Get tab index for tab key navigation"
          }
        },
        {
          "section": "Returns",
          "name": "onKeyNavigation",
          "data": {
            "order": 3,
            "name": "onKeyNavigation",
            "type": "(e: KeyboardEvent) => void",
            "description": "Function that handles on key down for navigation"
          }
        },
        {
          "section": "Returns",
          "name": "ref",
          "data": {
            "order": 4,
            "name": "ref",
            "type": "MutableRefObject",
            "description": "Ref object to use if ref isn't supplied in props"
          }
        },
        {
          "section": "Returns",
          "name": "selectedIndex",
          "data": {
            "order": 5,
            "name": "selectedIndex",
            "type": "number",
            "description": "Index of the selected listbox"
          }
        },
        {
          "section": "Returns",
          "name": "selectedIndices",
          "data": {
            "order": 6,
            "name": "selectedIndices",
            "type": "number[]",
            "description": "Indices of the selected listbox(s)"
          }
        },
        {
          "section": "Returns",
          "name": "toggleIndexSelected",
          "data": {
            "order": 7,
            "name": "toggleIndexSelected",
            "type": "(index: number) => void",
            "description": "Function that toggles selected state of listbox"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-pagination",
      "version": "0.0.1",
      "description": "This hook is used to manage pagination events, state, and visible page blocks. Supports both controlled and uncontrolled usage.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-pagination/use-pagination-example",
            "github": "apps/workshop/src/examples/hooks/use-pagination/use-pagination-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import {\n  VisaArrowEndTiny,\n  VisaArrowStartTiny,\n  VisaChevronLeftTiny,\n  VisaChevronRightTiny,\n  VisaOptionHorizontalTiny,\n} from '@visa/nova-icons-react';\nimport { Button, Pagination, PaginationOverflow, UtilityFragment, usePagination } from '@visa/nova-react';\n\nexport const UsePaginationExample = () => {\n  const {\n    isFirstPage,\n    isLastPage,\n    onFirstPage,\n    onLastPage,\n    onNextPage,\n    onPageChange,\n    onPreviousPage,\n    pages,\n    selectedPage,\n  } = usePagination({ maxPageNumber: 10, startPage: 1, totalPages: 12 });\n\n  return (\n    <nav aria-label=\"minimum and maximum pagination\" role=\"navigation\">\n      <UtilityFragment vAlignItems=\"center\" vGap={4}>\n        <Pagination>\n          <li>\n            <Button\n              aria-label=\"Go to first page\"\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={isFirstPage}\n              iconButton\n              onClick={onFirstPage}\n            >\n              <VisaArrowStartTiny rtl />\n            </Button>\n          </li>\n          <li>\n            <Button\n              aria-label=\"Go to previous page\"\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={isFirstPage}\n              iconButton\n              onClick={onPreviousPage}\n            >\n              <VisaChevronLeftTiny rtl />\n            </Button>\n          </li>\n          {pages.map((pageNumber, index) =>\n            pageNumber === -1 ? (\n              <UtilityFragment key={`min-max-pagination-ellipse-${index}`} vAlignItems=\"center\" vFlex>\n                <PaginationOverflow>\n                  <VisaOptionHorizontalTiny />\n                </PaginationOverflow>\n              </UtilityFragment>\n            ) : (\n              <li key={`min-max-pagination-page-${pageNumber}`}>\n                <Button\n                  aria-current={selectedPage === pageNumber}\n                  aria-label={`Page ${pageNumber}`}\n                  colorScheme=\"tertiary\"\n                  onClick={() => onPageChange(pageNumber as number)}\n                >\n                  {pageNumber}\n                </Button>\n              </li>\n            )\n          )}\n          <li>\n            <Button\n              aria-label=\"Go to next page\"\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={isLastPage}\n              iconButton\n              onClick={onNextPage}\n            >\n              <VisaChevronRightTiny rtl />\n            </Button>\n          </li>\n          <li>\n            <Button\n              aria-label=\"Go to last page\"\n              buttonSize=\"small\"\n              colorScheme=\"tertiary\"\n              disabled={isLastPage}\n              iconButton\n              onClick={onLastPage}\n            >\n              <VisaArrowEndTiny rtl />\n            </Button>\n          </li>\n        </Pagination>\n      </UtilityFragment>\n    </nav>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "blockMaxLength",
          "data": {
            "order": 1,
            "name": "blockMaxLength",
            "type": "number",
            "default": "",
            "required": "",
            "description": "Max block length for all blocks, this gets overwritten by `startBlockMaxLength`, `middleBlockMaxLength`, `endBlockMaxLength`"
          }
        },
        {
          "section": "Properties",
          "name": "compact",
          "data": {
            "order": 2,
            "name": "compact",
            "type": "boolean",
            "default": "",
            "required": "",
            "description": "Doesn't chunk pages"
          }
        },
        {
          "section": "Properties",
          "name": "defaultSelected",
          "data": {
            "order": 3,
            "name": "defaultSelected",
            "type": "number",
            "default": 1,
            "required": "",
            "description": "Default selected page"
          }
        },
        {
          "section": "Properties",
          "name": "endBlockMaxLength",
          "data": {
            "order": 4,
            "name": "endBlockMaxLength",
            "type": "number",
            "default": 3,
            "required": "",
            "description": "Maximum length of pages to show on the end pagination block"
          }
        },
        {
          "section": "Properties",
          "name": "maxPageNumber",
          "data": {
            "order": 5,
            "name": "maxPageNumber",
            "type": "number",
            "default": "",
            "required": "",
            "description": "Maximum page number to be shown, (default null for no maximum)"
          }
        },
        {
          "section": "Properties",
          "name": "middleBlockMaxLength",
          "data": {
            "order": 6,
            "name": "middleBlockMaxLength",
            "type": "number",
            "default": 3,
            "required": "",
            "description": "Maximum length of pages to show on the middle pagination block"
          }
        },
        {
          "section": "Properties",
          "name": "selectedPage",
          "data": {
            "order": 7,
            "name": "selectedPage",
            "type": "number",
            "default": "",
            "required": "",
            "description": "Currently selected page (controlled)"
          }
        },
        {
          "section": "Properties",
          "name": "separator",
          "data": {
            "order": 8,
            "name": "separator",
            "type": "string , number",
            "default": -1,
            "required": "",
            "description": "What to separate the pagination array up with, usually this separator will be replaced with icon or ellipses when shown in the UI"
          }
        },
        {
          "section": "Properties",
          "name": "setSelectedPage",
          "data": {
            "order": 9,
            "name": "setSelectedPage",
            "type": "(page: number) => void",
            "default": "",
            "required": "",
            "description": "Function to set the selected page (controlled)"
          }
        },
        {
          "section": "Properties",
          "name": "startBlockMaxLength",
          "data": {
            "order": 10,
            "name": "startBlockMaxLength",
            "type": "number",
            "default": 3,
            "required": "",
            "description": "Maximum length of pages to show on the start pagination block"
          }
        },
        {
          "section": "Properties",
          "name": "startPage",
          "data": {
            "order": 11,
            "name": "startPage",
            "type": "number",
            "default": 1,
            "required": "",
            "description": "Start from this page"
          }
        },
        {
          "section": "Properties",
          "name": "totalPages",
          "data": {
            "order": 12,
            "name": "totalPages",
            "type": "number",
            "default": "",
            "required": "yes",
            "description": "Length of total pages"
          }
        },
        {
          "section": "Returns",
          "name": "isFirstPage",
          "data": {
            "order": 1,
            "name": "isFirstPage",
            "type": "boolean",
            "description": "Is first page currently selected"
          }
        },
        {
          "section": "Returns",
          "name": "isLastPage",
          "data": {
            "order": 2,
            "name": "isLastPage",
            "type": "boolean",
            "description": "Is last page currently selected"
          }
        },
        {
          "section": "Returns",
          "name": "onFirstPage",
          "data": {
            "order": 3,
            "name": "onFirstPage",
            "type": "() => void",
            "description": "Event to handle first page selection"
          }
        },
        {
          "section": "Returns",
          "name": "onLastPage",
          "data": {
            "order": 4,
            "name": "onLastPage",
            "type": "() => void",
            "description": "Event to handle last page selection"
          }
        },
        {
          "section": "Returns",
          "name": "onNextPage",
          "data": {
            "order": 5,
            "name": "onNextPage",
            "type": "() => void",
            "description": "Event to handle next page selection"
          }
        },
        {
          "section": "Returns",
          "name": "onPageChange",
          "data": {
            "order": 6,
            "name": "onPageChange",
            "type": "(pageNumber: number) => void",
            "description": "Event to handle page selection"
          }
        },
        {
          "section": "Returns",
          "name": "onPreviousPage",
          "data": {
            "order": 7,
            "name": "onPreviousPage",
            "type": "() => void",
            "description": "Event to handle previous page selection"
          }
        },
        {
          "section": "Returns",
          "name": "pages",
          "data": {
            "order": 8,
            "name": "pages",
            "type": "(string , number)[]",
            "description": "Array of currently visible pages split by separator"
          }
        },
        {
          "section": "Returns",
          "name": "selectedPage",
          "data": {
            "order": 9,
            "name": "selectedPage",
            "type": "number",
            "description": "Currently selected page"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-tabs",
      "version": "0.0.1",
      "description": "This hook allows us to set the <defaultSelected> value, which indicates that we are selecting that item by default.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-tabs/use-tabs-example",
            "github": "apps/workshop/src/examples/hooks/use-tabs/use-tabs-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Button, Tab, Tabs, useTabs } from '@visa/nova-react';\n\nconst tabsList = ['Tab 1', 'Tab 2', 'Tab 3'];\n\nexport const UseTabsExample = () => {\n  const { getTabIndex, onIndexChange, onKeyNavigation, ref: tabsRef, selectedIndex } = useTabs();\n\n  return (\n    <Tabs onKeyDown={onKeyNavigation} role=\"tablist\">\n      {tabsList.map((tab, index) => (\n        <Tab key={`use-tabs-horizontal-tab-${index}`} role=\"none\">\n          <Button\n            aria-selected={index === selectedIndex}\n            buttonSize=\"large\"\n            colorScheme=\"tertiary\"\n            onClick={() => onIndexChange(index)}\n            ref={el => {\n              tabsRef.current[index] = el;\n            }}\n            role=\"tab\"\n            tabIndex={getTabIndex(index)}\n          >\n            {tab}\n          </Button>\n        </Tab>\n      ))}\n    </Tabs>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "arrowKeyNavigation",
          "data": {
            "order": 1,
            "name": "arrowKeyNavigation",
            "type": "\"none\" , \"both\" , \"horizontal\" , \"vertical\"",
            "default": "",
            "required": "",
            "description": "Arrow key navigation direction, 'horizontal', 'vertical', 'both', 'none'"
          }
        },
        {
          "section": "Properties",
          "name": "autoSelect",
          "data": {
            "order": 2,
            "name": "autoSelect",
            "type": "boolean",
            "default": "",
            "required": "",
            "description": "Auto select tab on keyboard navigation"
          }
        },
        {
          "section": "Properties",
          "name": "defaultSelected",
          "data": {
            "order": 3,
            "name": "defaultSelected",
            "type": "number",
            "default": -1,
            "required": "",
            "description": "Default selected tab"
          }
        },
        {
          "section": "Properties",
          "name": "onSelectedIndexChange",
          "data": {
            "order": 4,
            "name": "onSelectedIndexChange",
            "type": "(index: number) => void",
            "default": "",
            "required": "",
            "description": "Selected tab index change handler for controlled state, must also pass selected state"
          }
        },
        {
          "section": "Properties",
          "name": "ref",
          "data": {
            "order": 5,
            "name": "ref",
            "type": "RefObject",
            "default": "",
            "required": "",
            "description": "Ref for the tab elements"
          }
        },
        {
          "section": "Properties",
          "name": "selectedIndex",
          "data": {
            "order": 6,
            "name": "selectedIndex",
            "type": "number",
            "default": "",
            "required": "",
            "description": "Selected tab index for controlled state, must also pass onSelectedChange"
          }
        },
        {
          "section": "Returns",
          "name": "getTabIndex",
          "data": {
            "order": 1,
            "name": "getTabIndex",
            "type": "(index: number, disabled?: boolean) => -1 , 0",
            "description": "Get tab index for tab key navigation"
          }
        },
        {
          "section": "Returns",
          "name": "onIndexChange",
          "data": {
            "order": 2,
            "name": "onIndexChange",
            "type": "(index: number, disabled?: boolean) => void",
            "description": "Function that handles selected state of tabs"
          }
        },
        {
          "section": "Returns",
          "name": "onKeyNavigation",
          "data": {
            "order": 3,
            "name": "onKeyNavigation",
            "type": "(e: KeyboardEvent) => void",
            "description": "Function that handles on key down for navigation"
          }
        },
        {
          "section": "Returns",
          "name": "ref",
          "data": {
            "order": 4,
            "name": "ref",
            "type": "MutableRefObject",
            "description": "Ref object to use if ref isn't supplied in props"
          }
        },
        {
          "section": "Returns",
          "name": "selectedIndex",
          "data": {
            "order": 5,
            "name": "selectedIndex",
            "type": "number",
            "description": "Index of the selected tab"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "use-wizard",
      "version": "0.0.1",
      "description": "This hook is used to control the state of a wizard component.",
      "libraryId": null,
      "category": "hooks",
      "exampleSections": [
        {
          "name": "Behavior and usage",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Behavior and usage",
          "url": {
            "iframe": "hooks/use-wizard/use-wizard-example",
            "github": "apps/workshop/src/examples/hooks/use-wizard/use-wizard-example.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Badge, Button, Utility, Wizard, WizardStep, useWizard } from '@visa/nova-react';\nimport { VisaCheckmarkTiny, VisaChevronRightTiny, VisaErrorAltTiny } from '@visa/nova-icons-react';\n\nconst stepList = [\n  { title: 'Step label 1' },\n  { title: 'Step label 2' },\n  { title: 'Step label 3' },\n  { title: 'Step label 4' },\n  { title: 'Step label 5' },\n];\n\nexport const UseWizardExample = () => {\n  const {\n    currentStep,\n    isLastStep,\n    isStepAvailable,\n    isStepComplete,\n    isStepError,\n    onStepChange,\n    onStepComplete,\n    onStepError,\n    onStepNext,\n    onStepPrevious,\n    onStepReset,\n    onWizardReset,\n  } = useWizard({ length: stepList.length });\n\n  return (\n    <Utility vFlex vFlexCol vGap={12}>\n      <Wizard>\n        {stepList.map((step, i) => (\n          <WizardStep key={`horizontal-wizard-step-${i + 1}`}>\n            {isStepAvailable(i) ? (\n              <Button\n                className={`${\n                  currentStep === i ? 'v-typography-label-large-active' : 'v-typography-body-2'\n                } v-typography-color-default v-gap-8`}\n                colorScheme=\"tertiary\"\n                onClick={() => {\n                  onStepChange(i);\n                }}\n              >\n                <Badge\n                  active={currentStep === i && !isStepError(i) && !isStepComplete(i)}\n                  badgeType={(isStepError(i) && 'critical') || (isStepComplete(i) && 'stable') || 'subtle'}\n                  badgeVariant=\"icon\"\n                  clear={!(currentStep === i)}\n                  tag=\"span\"\n                >\n                  {isStepError(i) ? <VisaErrorAltTiny /> : isStepComplete(i) ? <VisaCheckmarkTiny /> : i + 1}\n                </Badge>\n                {step.title}\n                {i < stepList.length - 1 && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n              </Button>\n            ) : (\n              <>\n                <Badge badgeType=\"subtle\" badgeVariant=\"icon\" clear tag=\"span\">\n                  {i + 1}\n                </Badge>\n                {step.title}\n                {!isLastStep(i) && <VisaChevronRightTiny className=\"v-typography-color-subtle\" />}\n              </>\n            )}\n          </WizardStep>\n        ))}\n      </Wizard>\n      <Utility vFlex vFlexWrap vGap={24} vJustifyContent=\"between\">\n        <Button onClick={onStepPrevious}>Previous step</Button>\n        <Utility vFlex vFlexWrap vGap={12}>\n          <Button colorScheme=\"secondary\" onClick={() => onStepComplete(currentStep, { autoProgress: false })}>\n            Set step successful\n          </Button>\n          <Button colorScheme=\"secondary\" onClick={() => onStepError(currentStep, { autoProgress: false })}>\n            Set step error\n          </Button>\n          <Button colorScheme=\"secondary\" onClick={() => onStepReset(currentStep)}>\n            Reset current step\n          </Button>\n        </Utility>\n        <Button onClick={onStepNext}>Next step</Button>\n      </Utility>\n      <Utility vFlex vFlexWrap vGap={16} vJustifyContent=\"center\">\n        <Button destructive onClick={() => onWizardReset()}>\n          Reset wizard\n        </Button>\n        <Button colorScheme=\"secondary\" destructive onClick={() => onWizardReset(1)}>\n          Reset to step 2\n        </Button>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": ""
        }
      ],
      "apiSections": [
        {
          "name": "Properties",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 1
        },
        {
          "name": "Returns",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 2
        },
        {
          "name": "Client side only",
          "libraryId": null,
          "componentId": null,
          "description": "",
          "order": 3
        }
      ],
      "apiSectionValues": [
        {
          "section": "Properties",
          "name": "autoProgressComplete",
          "data": {
            "order": 1,
            "name": "autoProgressComplete",
            "type": "boolean",
            "default": true,
            "required": "",
            "description": "Auto progress on complete"
          }
        },
        {
          "section": "Properties",
          "name": "autoProgressError",
          "data": {
            "order": 2,
            "name": "autoProgressError",
            "type": "boolean",
            "default": "",
            "required": "",
            "description": "Auto progress on error"
          }
        },
        {
          "section": "Properties",
          "name": "defaultActiveStep",
          "data": {
            "order": 3,
            "name": "defaultActiveStep",
            "type": "number",
            "default": "",
            "required": "",
            "description": "Current step"
          }
        },
        {
          "section": "Properties",
          "name": "isExclusiveSets",
          "data": {
            "order": 4,
            "name": "isExclusiveSets",
            "type": "boolean",
            "default": true,
            "required": "",
            "description": "If the complete and error sets are mutually exclusive"
          }
        },
        {
          "section": "Properties",
          "name": "length",
          "data": {
            "order": 5,
            "name": "length",
            "type": "number",
            "default": "",
            "required": "yes",
            "description": "Length of steps"
          }
        },
        {
          "section": "Returns",
          "name": "currentStep",
          "data": {
            "order": 1,
            "name": "currentStep",
            "type": "number",
            "description": "Return the current step of the wizard"
          }
        },
        {
          "section": "Returns",
          "name": "hasError",
          "data": {
            "order": 2,
            "name": "hasError",
            "type": "() => boolean",
            "description": "Check if the wizard has any error step"
          }
        },
        {
          "section": "Returns",
          "name": "isStepAvailable",
          "data": {
            "order": 3,
            "name": "isStepAvailable",
            "type": "(index: number) => boolean",
            "description": "Check if the step is available"
          }
        },
        {
          "section": "Returns",
          "name": "isFirstStep",
          "data": {
            "order": 4,
            "name": "isFirstStep",
            "type": "(index: number) => boolean",
            "description": "Check if the current step is the first step"
          }
        },
        {
          "section": "Returns",
          "name": "isLastStep",
          "data": {
            "order": 5,
            "name": "isLastStep",
            "type": "(index: number) => boolean",
            "description": "Check if the current step is the last step"
          }
        },
        {
          "section": "Returns",
          "name": "isStepComplete",
          "data": {
            "order": 6,
            "name": "isStepComplete",
            "type": "(index: number) => boolean",
            "description": "Check if the step is completed"
          }
        },
        {
          "section": "Returns",
          "name": "isStepError",
          "data": {
            "order": 7,
            "name": "isStepError",
            "type": "(index: number) => boolean",
            "description": "Check if the step has an error"
          }
        },
        {
          "section": "Returns",
          "name": "isWizardComplete",
          "data": {
            "order": 8,
            "name": "isWizardComplete",
            "type": "() => boolean",
            "description": "Check if the wizard is complete"
          }
        },
        {
          "section": "Returns",
          "name": "maxStep",
          "data": {
            "order": 9,
            "name": "maxStep",
            "type": "number",
            "description": "Return the maximum available step of the wizard"
          }
        },
        {
          "section": "Returns",
          "name": "onStepChange",
          "data": {
            "order": 10,
            "name": "onStepChange",
            "type": "(index: number) => void",
            "description": "Move to the selected step"
          }
        },
        {
          "section": "Returns",
          "name": "onStepNext",
          "data": {
            "order": 11,
            "name": "onStepNext",
            "type": "() => void",
            "description": "Move to the next step"
          }
        },
        {
          "section": "Returns",
          "name": "onStepPrevious",
          "data": {
            "order": 12,
            "name": "onStepPrevious",
            "type": "() => void",
            "description": "Move to the previous step"
          }
        },
        {
          "section": "Returns",
          "name": "onStepComplete",
          "data": {
            "order": 13,
            "name": "onStepComplete",
            "type": "(index: number, { autoProgress = true }) => void",
            "description": "Mark the step as complete"
          }
        },
        {
          "section": "Returns",
          "name": "onStepError",
          "data": {
            "order": 14,
            "name": "onStepError",
            "type": "(index: number, { autoProgress = false }) => void",
            "description": "Mark the step as error"
          }
        },
        {
          "section": "Returns",
          "name": "onStepReset",
          "data": {
            "order": 15,
            "name": "onStepReset",
            "type": "(index: number) => void",
            "description": "Reset the step status"
          }
        },
        {
          "section": "Returns",
          "name": "onWizardReset",
          "data": {
            "order": 16,
            "name": "onWizardReset",
            "type": "(index: number) => void",
            "description": "Reset the wizard status (to the desired step)"
          }
        },
        {
          "section": "Client side only",
          "data": "true"
        }
      ]
    },
    {
      "name": "accessibility",
      "version": "0.0.1",
      "description": "Text elements to only be read by screen readers but not shown visually on screen.",
      "libraryId": null,
      "category": "utilities",
      "exampleSections": [
        {
          "name": "Accessibility utilities",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Accessibility utilities",
          "url": {
            "iframe": "utilities/accessibility/screen-reader-only-text",
            "github": "apps/workshop/src/examples/utilities/accessibility/screen-reader-only-text.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { ScreenReader } from '@visa/nova-react';\n\nexport const ScreenReaderOnlyText = () => {\n  return <ScreenReader>This text is not shown on the screen, but it's accessible to a screen reader.</ScreenReader>;\n};\n"
          },
          "name": "Screen reader-only text"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Accessibility utilities",
          "url": {
            "iframe": "utilities/accessibility/screen-reader-caption-within-table",
            "github": "apps/workshop/src/examples/utilities/accessibility/screen-reader-caption-within-table.tsx"
          },
          "tags": [
            "docs"
          ],
          "snippets": {
            "tsx": "import { ScreenReader, Table, TableWrapper, Tbody, Td, Tr } from '@visa/nova-react';\n\nexport const ScreenReaderCaptionWithinTable = () => {\n  return (\n    <TableWrapper>\n      <Table keyValue border>\n        <ScreenReader tag=\"caption\">Table with lined key-value pairs.</ScreenReader>\n        <Tbody>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 1\n            </th>\n            <Td>Value 1</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 2\n            </th>\n            <Td>Value 2</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 3\n            </th>\n            <Td>Value 3</Td>\n          </Tr>\n          <Tr>\n            <th className=\"v-td\" scope=\"row\">\n              Key 4\n            </th>\n            <Td>Value 4</Td>\n          </Tr>\n        </Tbody>\n      </Table>\n    </TableWrapper>\n  );\n};\n"
          },
          "name": "Screen reader-only table caption"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Utility",
          "selector": "<Utility />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component used to create a div, by default, with the correct Nova utility style classes applied."
        },
        {
          "order": 2,
          "name": "UtilityFragment",
          "selector": "<UtilityFragment />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Wraps around a component and add Nova utility classes to its direct child without adding extra elements to the DOM."
        },
        {
          "order": 3,
          "name": "Screenreader",
          "selector": "<ScreenReader />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Text elements to only be read by screen readers but not shown visually on screen."
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Utility",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Utility",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "vAlignContent",
          "section": "Utility",
          "data": {
            "name": "vAlignContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "Utility",
          "data": {
            "name": "vAlignItems",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "Utility",
          "data": {
            "name": "vAlignSelf",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "Utility",
          "data": {
            "name": "vColGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "Utility",
          "data": {
            "name": "vContainerHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "Utility",
          "data": {
            "name": "vElevation",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "Utility",
          "data": {
            "name": "vFlex",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "Utility",
          "data": {
            "name": "vFlexCol",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexColReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "Utility",
          "data": {
            "name": "vFlexInline",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexNoWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "Utility",
          "data": {
            "name": "vFlexRow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexRowReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "Utility",
          "data": {
            "name": "vGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "Utility",
          "data": {
            "name": "vHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "Utility",
          "data": {
            "name": "vJustifyContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "Utility",
          "data": {
            "name": "vMargin",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "Utility",
          "data": {
            "name": "vMarginBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "Utility",
          "data": {
            "name": "vMarginHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "Utility",
          "data": {
            "name": "vMarginLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "Utility",
          "data": {
            "name": "vMarginRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "Utility",
          "data": {
            "name": "vMarginTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "Utility",
          "data": {
            "name": "vMarginVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "Utility",
          "data": {
            "name": "vMediaHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "Utility",
          "data": {
            "name": "vPadding",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "Utility",
          "data": {
            "name": "vPaddingBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "Utility",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "Utility",
          "data": {
            "name": "vPaddingLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "Utility",
          "data": {
            "name": "vPaddingRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "Utility",
          "data": {
            "name": "vPaddingTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "Utility",
          "data": {
            "name": "vPaddingVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "Utility",
          "data": {
            "name": "vRowGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignItems",
            "type": "\"center\" , \"baseline\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignSelf",
            "type": "\"center\" , \"auto\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vColGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vContainerHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "UtilityFragment",
          "data": {
            "name": "vElevation",
            "type": "\"small\" , \"none\" , \"large\" , \"medium\" , \"inset\" , \"xlarge\" , \"xxlarge\" , \"xsmall\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlex",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexCol",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexColReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexInline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexNoWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRowReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vGap",
            "type": "Omit",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vHide",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vJustifyContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "UtilityFragment",
          "data": {
            "name": "vMargin",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vMediaHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "UtilityFragment",
          "data": {
            "name": "vPadding",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vRowGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "tag",
          "section": "Screenreader",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "span",
            "required": "false",
            "description": "Tag of Component"
          }
        }
      ]
    },
    {
      "name": "breakpoints",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "utilities",
      "exampleSections": [
        {
          "name": "Breakpoints",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Breakpoints",
          "url": {
            "iframe": "utilities/breakpoints/hide-breakpoints",
            "github": "apps/workshop/src/examples/utilities/breakpoints/hide-breakpoints.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar, Button, Utility } from '@visa/nova-react';\nimport { useState } from 'react';\n\nexport const HideBreakpoints = () => {\n  const [hide, setHide] = useState(false);\n  const [toggled, setToggled] = useState(false);\n\n  const toggleHide = (changedHide: boolean) => {\n    setHide(changedHide);\n    setToggled(true);\n  };\n\n  return (\n    <Utility vFlex vGap={24} vAlignItems=\"center\">\n      <Utility element={<Avatar>AM</Avatar>} vHide={hide} />\n      <span role=\"alert\" aria-live=\"polite\" className='v-sr'>\n          {toggled && (\n            hide? 'The avatar is hidden' : 'The avatar is visible'\n          )}\n        </span>\n      <Button colorScheme=\"secondary\" onClick={() => toggleHide(!hide)}>\n        {hide ? 'Show' : 'Hide'}\n      </Button>\n    </Utility>\n  );\n};\n"
          },
          "name": "Hide"
        },
        {
          "description": "In order for container queries to work, the container element must have a display value other than inline (e.g., block, flex, grid). Note that Angular elements (non-native HTML elements such as <app-root>) render display: inline by default, so you may need to change that in some cases.",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Breakpoints",
          "url": {
            "iframe": "utilities/breakpoints/container-hide-breakpoints",
            "github": "apps/workshop/src/examples/utilities/breakpoints/container-hide-breakpoints.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDeviceLaptopLow, VisaDeviceMobileLow } from '@visa/nova-icons-react';\nimport { Avatar, Utility, UtilityFragment } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const ContainerHideBreakpoints = () => {\n  return (\n    <Utility vFlex vFlexRow vGap={8} vFlexWrap style={{ containerType: 'inline-size' }}>\n      <UtilityFragment vContainerHide=\"xs\">\n        <Avatar style={{ '--v-avatar-background': '#e50000' } as CSSProperties}>XS</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"sm\">\n        <Avatar style={{ '--v-avatar-background': 'orange', '--v-avatar-foreground': 'black' } as CSSProperties}>\n          SM\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"md\">\n        <Avatar style={{ '--v-avatar-background': 'yellow', '--v-avatar-foreground': 'black' } as CSSProperties}>\n          MD\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"lg\">\n        <Avatar style={{ '--v-avatar-background': 'green' } as CSSProperties}>LG</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"xl\">\n        <Avatar style={{ '--v-avatar-background': 'blue' } as CSSProperties}>XL</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"xxl\">\n        <Avatar style={{ '--v-avatar-background': 'purple' } as CSSProperties}>XXL</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"mobile\">\n        <Avatar>\n          <VisaDeviceLaptopLow aria-label=\"Showing a laptop to indicate we're on a desktop-sized container\" />\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vContainerHide=\"desktop\">\n        <Avatar>\n          <VisaDeviceMobileLow aria-label=\"Showing a mobile device to indicate we're on a mobile-sized container\" />\n        </Avatar>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Hide with breakpoint-matching container query"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Breakpoints",
          "url": {
            "iframe": "utilities/breakpoints/media-hide-breakpoints",
            "github": "apps/workshop/src/examples/utilities/breakpoints/media-hide-breakpoints.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { VisaDeviceLaptopLow, VisaDeviceMobileLow } from '@visa/nova-icons-react';\nimport { Avatar, Utility, UtilityFragment } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MediaHideBreakpoints = () => {\n  return (\n    <Utility vFlex vFlexRow vGap={8} vFlexWrap style={{ containerType: 'inline-size' }}>\n      <UtilityFragment vMediaHide=\"xs\">\n        <Avatar style={{ '--v-avatar-background': '#e50000' } as CSSProperties}>XS</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"sm\">\n        <Avatar style={{ '--v-avatar-background': 'orange', '--v-avatar-foreground': 'black' } as CSSProperties}>\n          SM\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"md\">\n        <Avatar style={{ '--v-avatar-background': 'yellow', '--v-avatar-foreground': 'black' } as CSSProperties}>\n          MD\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"lg\">\n        <Avatar style={{ '--v-avatar-background': 'green' } as CSSProperties}>LG</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"xl\">\n        <Avatar style={{ '--v-avatar-background': 'blue' } as CSSProperties}>XL</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"xxl\">\n        <Avatar style={{ '--v-avatar-background': 'purple' } as CSSProperties}>XXL</Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"mobile\">\n        <Avatar>\n          <VisaDeviceLaptopLow aria-label=\"Showing a laptop to indicate we're on a desktop-sized media\" />\n        </Avatar>\n      </UtilityFragment>\n      <UtilityFragment vMediaHide=\"desktop\">\n        <Avatar>\n          <VisaDeviceMobileLow aria-label=\"Showing a mobile device to indicate we're on a mobile-sized media\" />\n        </Avatar>\n      </UtilityFragment>\n    </Utility>\n  );\n};\n"
          },
          "name": "Hide with breakpoint-matching media query"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Utility",
          "selector": "<Utility />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component used to create a div, by default, with the correct Nova utility style classes applied."
        },
        {
          "order": 2,
          "name": "UtilityFragment",
          "selector": "<UtilityFragment />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Wraps around a component and add Nova utility classes to its direct child without adding extra elements to the DOM."
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Utility",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Utility",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "vAlignContent",
          "section": "Utility",
          "data": {
            "name": "vAlignContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "Utility",
          "data": {
            "name": "vAlignItems",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "Utility",
          "data": {
            "name": "vAlignSelf",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "Utility",
          "data": {
            "name": "vColGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "Utility",
          "data": {
            "name": "vContainerHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "Utility",
          "data": {
            "name": "vElevation",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "Utility",
          "data": {
            "name": "vFlex",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "Utility",
          "data": {
            "name": "vFlexCol",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexColReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "Utility",
          "data": {
            "name": "vFlexInline",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexNoWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "Utility",
          "data": {
            "name": "vFlexRow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexRowReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "Utility",
          "data": {
            "name": "vGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "Utility",
          "data": {
            "name": "vHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "Utility",
          "data": {
            "name": "vJustifyContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "Utility",
          "data": {
            "name": "vMargin",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "Utility",
          "data": {
            "name": "vMarginBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "Utility",
          "data": {
            "name": "vMarginHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "Utility",
          "data": {
            "name": "vMarginLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "Utility",
          "data": {
            "name": "vMarginRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "Utility",
          "data": {
            "name": "vMarginTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "Utility",
          "data": {
            "name": "vMarginVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "Utility",
          "data": {
            "name": "vMediaHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "Utility",
          "data": {
            "name": "vPadding",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "Utility",
          "data": {
            "name": "vPaddingBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "Utility",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "Utility",
          "data": {
            "name": "vPaddingLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "Utility",
          "data": {
            "name": "vPaddingRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "Utility",
          "data": {
            "name": "vPaddingTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "Utility",
          "data": {
            "name": "vPaddingVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "Utility",
          "data": {
            "name": "vRowGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignItems",
            "type": "\"center\" , \"baseline\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignSelf",
            "type": "\"center\" , \"auto\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vColGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vContainerHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "UtilityFragment",
          "data": {
            "name": "vElevation",
            "type": "\"small\" , \"none\" , \"large\" , \"medium\" , \"inset\" , \"xlarge\" , \"xxlarge\" , \"xsmall\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlex",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexCol",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexColReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexInline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexNoWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRowReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vGap",
            "type": "Omit",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vHide",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vJustifyContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "UtilityFragment",
          "data": {
            "name": "vMargin",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vMediaHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "UtilityFragment",
          "data": {
            "name": "vPadding",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vRowGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        }
      ]
    },
    {
      "name": "elevation",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "utilities",
      "exampleSections": [
        {
          "name": "Elevations",
          "description": "",
          "order": 1
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Elevations",
          "url": {
            "iframe": "utilities/elevation/all-elevation",
            "github": "apps/workshop/src/examples/utilities/elevation/all-elevation.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\n// These styles simply makes a square box for demo purposes.\nconst defaultBoxStyle: CSSProperties = {\n  alignItems: 'center',\n  background: 'var(--palette-default-surface-2, #FFF)',\n  display: 'flex',\n  blockSize: 100,\n  inlineSize: 100,\n  justifyContent: 'center',\n};\n\nexport const AllElevation = () => {\n  return (\n    <Utility vFlex vFlexWrap vGap={12}>\n      <Utility vElevation=\"none\" style={defaultBoxStyle}>\n        None\n      </Utility>\n      <Utility vElevation=\"inset\" style={defaultBoxStyle}>\n        Inset\n      </Utility>\n      <Utility vElevation=\"xsmall\" style={defaultBoxStyle}>\n        XSmall\n      </Utility>\n      <Utility vElevation=\"small\" style={defaultBoxStyle}>\n        Small\n      </Utility>\n      <Utility vElevation=\"medium\" style={defaultBoxStyle}>\n        Medium\n      </Utility>\n      <Utility vElevation=\"large\" style={defaultBoxStyle}>\n        Large\n      </Utility>\n      <Utility vElevation=\"xlarge\" style={defaultBoxStyle}>\n        XLarge\n      </Utility>\n      <Utility vElevation=\"xxlarge\" style={defaultBoxStyle}>\n        XXLarge\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "All elevations"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Utility",
          "selector": "<Utility />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component used to create a div, by default, with the correct Nova utility style classes applied."
        },
        {
          "order": 2,
          "name": "UtilityFragment",
          "selector": "<UtilityFragment />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Wraps around a component and add Nova utility classes to its direct child without adding extra elements to the DOM."
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Utility",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Utility",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "vAlignContent",
          "section": "Utility",
          "data": {
            "name": "vAlignContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "Utility",
          "data": {
            "name": "vAlignItems",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "Utility",
          "data": {
            "name": "vAlignSelf",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "Utility",
          "data": {
            "name": "vColGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "Utility",
          "data": {
            "name": "vContainerHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "Utility",
          "data": {
            "name": "vElevation",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "Utility",
          "data": {
            "name": "vFlex",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "Utility",
          "data": {
            "name": "vFlexCol",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexColReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "Utility",
          "data": {
            "name": "vFlexInline",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexNoWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "Utility",
          "data": {
            "name": "vFlexRow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexRowReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "Utility",
          "data": {
            "name": "vGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "Utility",
          "data": {
            "name": "vHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "Utility",
          "data": {
            "name": "vJustifyContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "Utility",
          "data": {
            "name": "vMargin",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "Utility",
          "data": {
            "name": "vMarginBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "Utility",
          "data": {
            "name": "vMarginHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "Utility",
          "data": {
            "name": "vMarginLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "Utility",
          "data": {
            "name": "vMarginRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "Utility",
          "data": {
            "name": "vMarginTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "Utility",
          "data": {
            "name": "vMarginVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "Utility",
          "data": {
            "name": "vMediaHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "Utility",
          "data": {
            "name": "vPadding",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "Utility",
          "data": {
            "name": "vPaddingBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "Utility",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "Utility",
          "data": {
            "name": "vPaddingLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "Utility",
          "data": {
            "name": "vPaddingRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "Utility",
          "data": {
            "name": "vPaddingTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "Utility",
          "data": {
            "name": "vPaddingVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "Utility",
          "data": {
            "name": "vRowGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignItems",
            "type": "\"center\" , \"baseline\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignSelf",
            "type": "\"center\" , \"auto\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vColGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vContainerHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "UtilityFragment",
          "data": {
            "name": "vElevation",
            "type": "\"small\" , \"none\" , \"large\" , \"medium\" , \"inset\" , \"xlarge\" , \"xxlarge\" , \"xsmall\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlex",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexCol",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexColReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexInline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexNoWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRowReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vGap",
            "type": "Omit",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vHide",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vJustifyContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "UtilityFragment",
          "data": {
            "name": "vMargin",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vMediaHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "UtilityFragment",
          "data": {
            "name": "vPadding",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vRowGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        }
      ]
    },
    {
      "name": "flex",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "utilities",
      "exampleSections": [
        {
          "name": "Flex displays",
          "description": "",
          "order": 1
        },
        {
          "name": "Flex column",
          "description": "",
          "order": 2
        },
        {
          "name": "Flex row",
          "description": "",
          "order": 3
        },
        {
          "name": "Flex wrap",
          "description": "",
          "order": 4
        },
        {
          "name": "Flex grow",
          "description": "",
          "order": 5
        },
        {
          "name": "Flex shrink",
          "description": "",
          "order": 6
        },
        {
          "name": "Flex align",
          "description": "",
          "order": 7
        },
        {
          "name": "Flex justify",
          "description": "",
          "order": 8
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Flex displays",
          "url": {
            "iframe": "utilities/flex/default-flex",
            "github": "apps/workshop/src/examples/utilities/flex/default-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const DefaultFlex = () => {\n  return (\n    <Utility vFlex vGap={4}>\n      This is a flex container\n    </Utility>\n  );\n};\n"
          },
          "name": "Flex default"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Flex displays",
          "url": {
            "iframe": "utilities/flex/inline-flex",
            "github": "apps/workshop/src/examples/utilities/flex/inline-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const InlineFlex = () => {\n  return (\n    <Utility vFlexInline vGap={4}>\n      This is an inline flex container\n    </Utility>\n  );\n};\n"
          },
          "name": "Inline flex"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Flex column",
          "url": {
            "iframe": "utilities/flex/column-flex",
            "github": "apps/workshop/src/examples/utilities/flex/column-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const ColumnFlex = () => {\n  return (\n    <Utility vFlex vFlexCol vGap={4}>\n      <span>first</span>\n      <span>second</span>\n      <span>third</span>\n    </Utility>\n  );\n};\n"
          },
          "name": "Flex column"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Flex column",
          "url": {
            "iframe": "utilities/flex/column-reverse-flex",
            "github": "apps/workshop/src/examples/utilities/flex/column-reverse-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const ColumnReverseFlex = () => {\n  return (\n    <Utility vFlex vFlexColReverse vGap={4}>\n      <span>first</span>\n      <span>second</span>\n      <span>third</span>\n    </Utility>\n  );\n};\n"
          },
          "name": "Flex column reverse"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Flex row",
          "url": {
            "iframe": "utilities/flex/row-flex",
            "github": "apps/workshop/src/examples/utilities/flex/row-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const RowFlex = () => {\n  return (\n    <Utility vFlex vFlexRow vGap={4}>\n      <span>first</span>\n      <span>second</span>\n      <span>third</span>\n    </Utility>\n  );\n};\n"
          },
          "name": "Flex row"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Flex row",
          "url": {
            "iframe": "utilities/flex/row-reverse-flex",
            "github": "apps/workshop/src/examples/utilities/flex/row-reverse-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Utility } from '@visa/nova-react';\n\nexport const RowReverseFlex = () => {\n  return (\n    <Utility vFlex vFlexRowReverse vGap={4}>\n      <span>first</span>\n      <span>second</span>\n      <span>third</span>\n    </Utility>\n  );\n};\n"
          },
          "name": "Flex row reverse"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Flex wrap",
          "url": {
            "iframe": "utilities/flex/wrap-flex",
            "github": "apps/workshop/src/examples/utilities/flex/wrap-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const WrapFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexWrap vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px', '--v-surface-inline-size': '150px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n        <span>fifth</span>\n        <span>sixth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex wrap"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Flex wrap",
          "url": {
            "iframe": "utilities/flex/wrap-reverse-flex",
            "github": "apps/workshop/src/examples/utilities/flex/wrap-reverse-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const WrapReverseFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrapReverse vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px', '--v-surface-inline-size': '150px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n        <span>fifth</span>\n        <span>sixth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex wrap reverse"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Flex wrap",
          "url": {
            "iframe": "utilities/flex/no-wrap-flex",
            "github": "apps/workshop/src/examples/utilities/flex/no-wrap-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const NoWrapFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexNoWrap vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px', '--v-surface-inline-size': '150px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n        <span>fifth</span>\n        <span>sixth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex no wrap"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Flex grow",
          "url": {
            "iframe": "utilities/flex/grow-flex",
            "github": "apps/workshop/src/examples/utilities/flex/grow-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\nexport const GrowFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <Utility tag=\"span\" vFlexGrow>\n          first\n        </Utility>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex grow"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Flex grow",
          "url": {
            "iframe": "utilities/flex/grow-zero-flex",
            "github": "apps/workshop/src/examples/utilities/flex/grow-zero-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\nexport const GrowZeroFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <Utility tag=\"span\" vFlexGrow0>\n          first\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          second\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          third\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          fourth\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex grow 0"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Flex shrink",
          "url": {
            "iframe": "utilities/flex/shrink-flex",
            "github": "apps/workshop/src/examples/utilities/flex/shrink-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\nexport const ShrinkFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <Utility tag=\"span\" vFlexShrink>\n          first\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          second\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          third\n        </Utility>\n        <Utility tag=\"span\" vFlexGrow>\n          fourth\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex shrink"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Flex shrink",
          "url": {
            "iframe": "utilities/flex/shrink-zero-flex",
            "github": "apps/workshop/src/examples/utilities/flex/shrink-zero-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, Utility, UtilityFragment } from '@visa/nova-react';\n\nexport const ShrinkZeroFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4} vFlexWrap>\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <Utility tag=\"span\" vFlexShrink0>\n          first\n        </Utility>\n        <Utility tag=\"span\" vFlexShrink>\n          second\n        </Utility>\n        <Utility tag=\"span\" vFlexShrink>\n          third\n        </Utility>\n        <Utility tag=\"span\" vFlexShrink>\n          fourth\n        </Utility>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex shrink 0"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-center-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-center-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentCenterFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"center\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content center"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-start-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-start-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentStartFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"start\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content start"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-end-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-end-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentEndFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"end\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content end"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-between-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-between-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentBetweenFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"between\" vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content space between"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-around-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-around-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentAroundFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"around\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content around"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-content-evenly-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-content-evenly-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignContentEvenlyFlex = () => {\n  return (\n    <UtilityFragment vAlignContent=\"evenly\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align content evenly"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-items-start-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-items-start-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignItemsStartFlex = () => {\n  return (\n    <UtilityFragment vAlignItems=\"start\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align items start"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-items-end-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-items-end-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignItemsEndFlex = () => {\n  return (\n    <UtilityFragment vAlignItems=\"end\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align items end"
        },
        {
          "description": "",
          "order": 22,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-items-center-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-items-center-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignItemsCenterFlex = () => {\n  return (\n    <UtilityFragment vAlignItems=\"center\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align items center"
        },
        {
          "description": "",
          "order": 23,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-items-baseline-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-items-baseline-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignItemsBaselineFlex = () => {\n  return (\n    <UtilityFragment vAlignItems=\"baseline\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align items baseline"
        },
        {
          "description": "",
          "order": 24,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-items-stretch-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-items-stretch-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignItemsStretchFlex = () => {\n  return (\n    <UtilityFragment vAlignItems=\"stretch\" vFlex vFlexRow vFlexWrap vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align items stretch"
        },
        {
          "description": "",
          "order": 25,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-self-start-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-self-start-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignSelfStartFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <UtilityFragment vFlex vAlignSelf=\"start\">\n          <Surface surfaceType=\"alternate\">self</Surface>\n        </UtilityFragment>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align self start"
        },
        {
          "description": "",
          "order": 26,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-self-end-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-self-end-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignSelfEndFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <UtilityFragment vFlex vAlignSelf=\"end\">\n          <Surface surfaceType=\"alternate\">self</Surface>\n        </UtilityFragment>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align self end"
        },
        {
          "description": "",
          "order": 27,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-self-auto-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-self-auto-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignSelfAutoFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <UtilityFragment vAlignSelf=\"auto\" vFlex>\n          <Surface surfaceType=\"alternate\">self</Surface>\n        </UtilityFragment>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align self auto"
        },
        {
          "description": "",
          "order": 28,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-self-center-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-self-center-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignSelfCenterFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <UtilityFragment vAlignSelf=\"center\" vFlex>\n          <Surface surfaceType=\"alternate\">self</Surface>\n        </UtilityFragment>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align self center"
        },
        {
          "description": "",
          "order": 29,
          "libraryId": null,
          "componentId": null,
          "section": "Flex align",
          "url": {
            "iframe": "utilities/flex/align-self-stretch-flex",
            "github": "apps/workshop/src/examples/utilities/flex/align-self-stretch-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const AlignSelfStretchFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vGap={4}>\n      <Surface style={{ blockSize: '80px', '--v-surface-border-size': '2px' } as CSSProperties}>\n        <UtilityFragment vFlex vAlignSelf=\"stretch\">\n          <Surface surfaceType=\"alternate\">self</Surface>\n        </UtilityFragment>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex align self stretch"
        },
        {
          "description": "",
          "order": 30,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-start-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-start-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentStartFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4} vJustifyContent=\"start\">\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content start"
        },
        {
          "description": "",
          "order": 31,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-end-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-end-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentEndFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4} vJustifyContent=\"end\">\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content end"
        },
        {
          "description": "",
          "order": 32,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-center-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-center-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentCenterFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4} vJustifyContent=\"center\">\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content center"
        },
        {
          "description": "",
          "order": 33,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-between-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-between-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentBetweenFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vJustifyContent=\"between\" vGap={4}>\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content space between"
        },
        {
          "description": "",
          "order": 34,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-around-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-around-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentAroundFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4} vJustifyContent=\"around\">\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content around"
        },
        {
          "description": "",
          "order": 35,
          "libraryId": null,
          "componentId": null,
          "section": "Flex justify",
          "url": {
            "iframe": "utilities/flex/justify-content-evenly-flex",
            "github": "apps/workshop/src/examples/utilities/flex/justify-content-evenly-flex.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import type { CSSProperties } from 'react';\n\nimport { Surface, UtilityFragment } from '@visa/nova-react';\n\nexport const JustifyContentEvenlyFlex = () => {\n  return (\n    <UtilityFragment vFlex vFlexRow vFlexWrap vGap={4} vJustifyContent=\"evenly\">\n      <Surface style={{ '--v-surface-border-size': '2px' } as CSSProperties}>\n        <span>first</span>\n        <span>second</span>\n        <span>third</span>\n        <span>fourth</span>\n      </Surface>\n    </UtilityFragment>\n  );\n};\n"
          },
          "name": "Flex justify content evenly"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Utility",
          "selector": "<Utility />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component used to create a div, by default, with the correct Nova utility style classes applied."
        },
        {
          "order": 2,
          "name": "UtilityFragment",
          "selector": "<UtilityFragment />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Wraps around a component and add Nova utility classes to its direct child without adding extra elements to the DOM."
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Utility",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Utility",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "vAlignContent",
          "section": "Utility",
          "data": {
            "name": "vAlignContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "Utility",
          "data": {
            "name": "vAlignItems",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "Utility",
          "data": {
            "name": "vAlignSelf",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "Utility",
          "data": {
            "name": "vColGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "Utility",
          "data": {
            "name": "vContainerHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "Utility",
          "data": {
            "name": "vElevation",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "Utility",
          "data": {
            "name": "vFlex",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "Utility",
          "data": {
            "name": "vFlexCol",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexColReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "Utility",
          "data": {
            "name": "vFlexInline",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexNoWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "Utility",
          "data": {
            "name": "vFlexRow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexRowReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "Utility",
          "data": {
            "name": "vGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "Utility",
          "data": {
            "name": "vHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "Utility",
          "data": {
            "name": "vJustifyContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "Utility",
          "data": {
            "name": "vMargin",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "Utility",
          "data": {
            "name": "vMarginBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "Utility",
          "data": {
            "name": "vMarginHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "Utility",
          "data": {
            "name": "vMarginLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "Utility",
          "data": {
            "name": "vMarginRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "Utility",
          "data": {
            "name": "vMarginTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "Utility",
          "data": {
            "name": "vMarginVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "Utility",
          "data": {
            "name": "vMediaHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "Utility",
          "data": {
            "name": "vPadding",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "Utility",
          "data": {
            "name": "vPaddingBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "Utility",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "Utility",
          "data": {
            "name": "vPaddingLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "Utility",
          "data": {
            "name": "vPaddingRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "Utility",
          "data": {
            "name": "vPaddingTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "Utility",
          "data": {
            "name": "vPaddingVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "Utility",
          "data": {
            "name": "vRowGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignItems",
            "type": "\"center\" , \"baseline\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignSelf",
            "type": "\"center\" , \"auto\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vColGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vContainerHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "UtilityFragment",
          "data": {
            "name": "vElevation",
            "type": "\"small\" , \"none\" , \"large\" , \"medium\" , \"inset\" , \"xlarge\" , \"xxlarge\" , \"xsmall\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlex",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexCol",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexColReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexInline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexNoWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRowReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vGap",
            "type": "Omit",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vHide",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vJustifyContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "UtilityFragment",
          "data": {
            "name": "vMargin",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vMediaHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "UtilityFragment",
          "data": {
            "name": "vPadding",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vRowGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        }
      ]
    },
    {
      "name": "spacing",
      "version": "0.0.1",
      "description": "",
      "libraryId": null,
      "category": "utilities",
      "exampleSections": [
        {
          "name": "Gap",
          "description": "",
          "order": 1
        },
        {
          "name": "Margin",
          "description": "",
          "order": 2
        },
        {
          "name": "Padding",
          "description": "",
          "order": 3
        }
      ],
      "examples": [
        {
          "description": "",
          "order": 1,
          "libraryId": null,
          "componentId": null,
          "section": "Gap",
          "url": {
            "iframe": "utilities/spacing/gap-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/gap-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const GapSpacing = () => {\n  const itemCardStyles = { boxShadow: 'var(--elevation-medium)', inlineSize: 'auto' } as CSSProperties;\n  return (\n    <Utility vFlex>\n      <Utility vFlex vColGap={20} style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n          Item 1\n        </Utility>\n        <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n          Item 2\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default gap"
        },
        {
          "description": "",
          "order": 2,
          "libraryId": null,
          "componentId": null,
          "section": "Gap",
          "url": {
            "iframe": "utilities/spacing/gap-column-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/gap-column-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const GapColumnSpacing = () => {\n  const itemCardStyles = { boxShadow: 'var(--elevation-medium)', inlineSize: 'auto' } as CSSProperties;\n\n  return (\n    <Utility vFlex>\n      <Utility vFlex vColGap={20} style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility vFlex vFlexCol>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 1\n          </Utility>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 3\n          </Utility>\n        </Utility>\n        <Utility vFlex vFlexCol>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 2\n          </Utility>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 4\n          </Utility>\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Column gap"
        },
        {
          "description": "",
          "order": 3,
          "libraryId": null,
          "componentId": null,
          "section": "Gap",
          "url": {
            "iframe": "utilities/spacing/gap-row-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/gap-row-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const GapRowSpacing = () => {\n  const itemCardStyles = { boxShadow: 'var(--elevation-medium)', inlineSize: 'auto' } as CSSProperties;\n\n  return (\n    <Utility vFlex>\n      <Utility\n        vFlex\n        vFlexCol\n        vRowGap={20}\n        style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}\n      >\n        <Utility vFlex>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 1\n          </Utility>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 2\n          </Utility>\n        </Utility>\n        <Utility vFlex>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 3\n          </Utility>\n          <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n            Item 4\n          </Utility>\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Row gap"
        },
        {
          "description": "",
          "order": 4,
          "libraryId": null,
          "componentId": null,
          "section": "Gap",
          "url": {
            "iframe": "utilities/spacing/gap-normal-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/gap-normal-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const GapNormalSpacing = () => {\n  const itemCardStyles = { boxShadow: 'var(--elevation-medium)', inlineSize: 'auto' } as CSSProperties;\n  return (\n    <Utility vFlex>\n      <Utility vFlex vGap=\"normal\" style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n          Item 1\n        </Utility>\n        <Utility vFlexGrow vPadding={16} style={itemCardStyles} element={<Surface />}>\n          Item 2\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Gap normal"
        },
        {
          "description": "",
          "order": 5,
          "libraryId": null,
          "componentId": null,
          "section": "Gap",
          "url": {
            "iframe": "utilities/spacing/gap-inherit-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/gap-inherit-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Avatar, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nconst userCardStyles = {\n  background: 'var(--palette-default-surface-1)',\n  padding: 'var(--size-scalable-6) var(--size-scalable-80) var(--size-scalable-6) var(--size-scalable-20)',\n} as CSSProperties;\n\nconst users = [\n  {\n    name: 'Alex Miller',\n    initials: 'AM',\n  },\n  {\n    name: 'Rosetta Jones',\n    initials: 'RJ',\n  },\n  {\n    name: 'Stacey Taylor',\n    initials: 'ST',\n  },\n];\n\nexport const GapInheritSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        element={<ul />}\n        vFlex\n        vFlexCol\n        vGap={8}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n          } as CSSProperties\n        }\n      >\n        {users.map(u => (\n          <Utility key={u.name} element={<li />} vFlex vAlignItems=\"center\" vGap=\"inherit\" style={userCardStyles}>\n            <Avatar small aria-label={u.name}>\n              {u.initials}\n            </Avatar>\n            {u.name}\n          </Utility>\n        ))}\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Gap inherit"
        },
        {
          "description": "",
          "order": 6,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/default-margin",
            "github": "apps/workshop/src/examples/utilities/spacing/default-margin.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const DefaultMargin = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMargin={20}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Default margin"
        },
        {
          "description": "",
          "order": 7,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-top-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-top-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginTopSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginTop={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin top"
        },
        {
          "description": "",
          "order": 8,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-bottom-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-bottom-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginBottomSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginBottom={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin bottom"
        },
        {
          "description": "",
          "order": 9,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-left-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-left-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginLeftSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginLeft={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin left"
        },
        {
          "description": "",
          "order": 10,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-right-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-right-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginRightSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginRight={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin right"
        },
        {
          "description": "",
          "order": 11,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-horizontal-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-horizontal-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginHorizontalSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginHorizontal={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin horizontal"
        },
        {
          "description": "",
          "order": 12,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-vertical-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-vertical-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginVerticalSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility vFlex style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          element={<Surface />}\n          vMarginVertical={20}\n          vPadding={16}\n          style={{ border: '1px dashed var(--palette-default-active-subtle)' } as CSSProperties}\n        >\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin vertical"
        },
        {
          "description": "",
          "order": 13,
          "libraryId": null,
          "componentId": null,
          "section": "Margin",
          "url": {
            "iframe": "utilities/spacing/margin-inherit-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/margin-inherit-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const MarginInheritSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility style={{ background: 'var(--palette-default-surface-highlight)' } as CSSProperties}>\n        <Utility\n          vMarginTop={20}\n          style={\n            {\n              textAlign: 'center',\n              border: '1px dashed var(--palette-default-active-subtle)',\n              background: 'var(--palette-messaging-highlight-positive)',\n            } as CSSProperties\n          }\n        >\n          <p>Parent with top margin</p>\n          <Utility\n            element={<Surface />}\n            vMarginTop=\"inherit\"\n            vPadding={16}\n            style={\n              {\n                border: '1px dashed var(--palette-default-active-subtle)',\n                borderInline: 0,\n                borderBlockEnd: 0,\n              } as CSSProperties\n            }\n          >\n            Child inherits top margin from parent\n          </Utility>\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Margin inherit"
        },
        {
          "description": "",
          "order": 14,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/default-padding",
            "github": "apps/workshop/src/examples/utilities/spacing/default-padding.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const DefaultPadding = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPadding={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding"
        },
        {
          "description": "",
          "order": 15,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-top-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-top-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingTopSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingTop={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n\n\n"
          },
          "name": "Padding top"
        },
        {
          "description": "",
          "order": 16,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-bottom-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-bottom-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingBottomSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingBottom={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding bottom"
        },
        {
          "description": "",
          "order": 17,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-left-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-left-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingLeftSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingLeft={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding left"
        },
        {
          "description": "",
          "order": 18,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-right-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-right-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingRightSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingRight={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n\n"
          },
          "name": "Padding right"
        },
        {
          "description": "",
          "order": 19,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-horizontal-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-horizontal-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingHorizontalSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingHorizontal={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding horizontal"
        },
        {
          "description": "",
          "order": 20,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-vertical-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-vertical-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingVerticalSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingVertical={20}\n        style={\n          {\n            background: 'var(--palette-default-surface-highlight)',\n            border: '1px dashed var(--palette-default-active-subtle)',\n          } as CSSProperties\n        }\n      >\n        <Utility vPadding={16} element={<Surface />} vPaddingBottom={20}>\n          Content Area\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding vertical"
        },
        {
          "description": "",
          "order": 21,
          "libraryId": null,
          "componentId": null,
          "section": "Padding",
          "url": {
            "iframe": "utilities/spacing/padding-inherit-spacing",
            "github": "apps/workshop/src/examples/utilities/spacing/padding-inherit-spacing.tsx"
          },
          "tags": [],
          "snippets": {
            "tsx": "import { Surface, Utility } from '@visa/nova-react';\nimport type { CSSProperties } from 'react';\n\nexport const PaddingInheritSpacing = () => {\n  return (\n    <Utility vFlex>\n      <Utility\n        vPaddingTop={24}\n        style={\n          {\n            textAlign: 'center',\n            border: '1px dashed var(--palette-default-active-subtle)',\n            background: 'var(--palette-default-surface-highlight)',\n          } as CSSProperties\n        }\n      >\n        <p>Parent with top padding</p>\n        <Utility\n          element={<Surface />}\n          vPaddingTop=\"inherit\"\n          vPadding={16}\n          style={\n            {\n              border: '1px dashed var(--palette-default-active-subtle)',\n              borderInline: 0,\n              borderBlockEnd: 0,\n            } as CSSProperties\n          }\n        >\n          Child inherits top margin from parent\n        </Utility>\n      </Utility>\n    </Utility>\n  );\n};\n"
          },
          "name": "Padding inherit"
        }
      ],
      "propertySections": [
        {
          "order": 1,
          "name": "Utility",
          "selector": "<Utility />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Component used to create a div, by default, with the correct Nova utility style classes applied."
        },
        {
          "order": 2,
          "name": "UtilityFragment",
          "selector": "<UtilityFragment />",
          "libraryId": null,
          "componentId": null,
          "type": "components",
          "description": "Wraps around a component and add Nova utility classes to its direct child without adding extra elements to the DOM."
        }
      ],
      "properties": [
        {
          "name": "element",
          "section": "Utility",
          "data": {
            "name": "element",
            "type": "ReactElement",
            "default": "",
            "required": "false",
            "description": "Cloned Element (not compatible with tag property)"
          }
        },
        {
          "name": "tag",
          "section": "Utility",
          "data": {
            "name": "tag",
            "type": "ElementType",
            "default": "div",
            "required": "false",
            "description": "Tag (not compatible with element property)"
          }
        },
        {
          "name": "vAlignContent",
          "section": "Utility",
          "data": {
            "name": "vAlignContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "Utility",
          "data": {
            "name": "vAlignItems",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "Utility",
          "data": {
            "name": "vAlignSelf",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "Utility",
          "data": {
            "name": "vColGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "Utility",
          "data": {
            "name": "vContainerHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "Utility",
          "data": {
            "name": "vElevation",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "Utility",
          "data": {
            "name": "vFlex",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "Utility",
          "data": {
            "name": "vFlexCol",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexColReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "Utility",
          "data": {
            "name": "vFlexGrow0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "Utility",
          "data": {
            "name": "vFlexInline",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexNoWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "Utility",
          "data": {
            "name": "vFlexRow",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexRowReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "Utility",
          "data": {
            "name": "vFlexShrink0",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "Utility",
          "data": {
            "name": "vFlexWrap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "Utility",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "Utility",
          "data": {
            "name": "vGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "Utility",
          "data": {
            "name": "vHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "Utility",
          "data": {
            "name": "vJustifyContent",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "Utility",
          "data": {
            "name": "vMargin",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "Utility",
          "data": {
            "name": "vMarginBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "Utility",
          "data": {
            "name": "vMarginHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "Utility",
          "data": {
            "name": "vMarginLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "Utility",
          "data": {
            "name": "vMarginRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "Utility",
          "data": {
            "name": "vMarginTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "Utility",
          "data": {
            "name": "vMarginVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "Utility",
          "data": {
            "name": "vMediaHide",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "Utility",
          "data": {
            "name": "vPadding",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "Utility",
          "data": {
            "name": "vPaddingBottom",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "Utility",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "Utility",
          "data": {
            "name": "vPaddingLeft",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "Utility",
          "data": {
            "name": "vPaddingRight",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "Utility",
          "data": {
            "name": "vPaddingTop",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "Utility",
          "data": {
            "name": "vPaddingVertical",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "Utility",
          "data": {
            "name": "vRowGap",
            "type": "any",
            "default": "",
            "required": "true",
            "description": ""
          }
        },
        {
          "name": "vAlignContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignItems",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignItems",
            "type": "\"center\" , \"baseline\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vAlignSelf",
          "section": "UtilityFragment",
          "data": {
            "name": "vAlignSelf",
            "type": "\"center\" , \"auto\" , \"end\" , \"start\" , \"stretch\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vColGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vColGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vContainerHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vContainerHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vElevation",
          "section": "UtilityFragment",
          "data": {
            "name": "vElevation",
            "type": "\"small\" , \"none\" , \"large\" , \"medium\" , \"inset\" , \"xlarge\" , \"xxlarge\" , \"xsmall\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlex",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlex",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexCol",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexCol",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexColReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexColReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexGrow0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexGrow0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexInline",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexInline",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexNoWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexNoWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRow",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRow",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexRowReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexRowReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexShrink0",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexShrink0",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrap",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrap",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vFlexWrapReverse",
          "section": "UtilityFragment",
          "data": {
            "name": "vFlexWrapReverse",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vGap",
            "type": "Omit",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vHide",
            "type": "boolean",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vJustifyContent",
          "section": "UtilityFragment",
          "data": {
            "name": "vJustifyContent",
            "type": "\"center\" , \"end\" , \"start\" , \"around\" , \"between\" , \"evenly\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMargin",
          "section": "UtilityFragment",
          "data": {
            "name": "vMargin",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMarginVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vMarginVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vMediaHide",
          "section": "UtilityFragment",
          "data": {
            "name": "vMediaHide",
            "type": "\"xs\" , \"sm\" , \"md\" , \"lg\" , \"xl\" , \"xxl\" , \"desktop\" , \"mobile\"",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPadding",
          "section": "UtilityFragment",
          "data": {
            "name": "vPadding",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingBottom",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingBottom",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingHorizontal",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingHorizontal",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingLeft",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingLeft",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingRight",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingRight",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingTop",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingTop",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vPaddingVertical",
          "section": "UtilityFragment",
          "data": {
            "name": "vPaddingVertical",
            "type": "0 , 1 , \"inherit\" , \"auto\" , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        },
        {
          "name": "vRowGap",
          "section": "UtilityFragment",
          "data": {
            "name": "vRowGap",
            "type": "0 , 1 , 48 , 4 , 10 , 3 , 2 , 5 , 6 , 7 , 8 , 9 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47",
            "default": "",
            "required": "false",
            "description": ""
          }
        }
      ]
    }
  ]
}