@poupe/vue
Version:
Vue component library for Poupe UI framework with theme customization and accessibility support
1 lines • 43.1 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/story/code-block.vue","../../src/components/story/code-block.vue","../../src/components/story/showcase-item.vue","../../src/components/story/showcase-item.vue","../../src/components/story/utils.ts","../../src/components/story/renderer.vue","../../src/components/story/renderer.vue","../../src/components/story/section.vue","../../src/components/story/section.vue","../../src/components/story/showcase.vue","../../src/components/story/showcase.vue","../../src/components/story/group-renderer.vue","../../src/components/story/group-renderer.vue","../../src/components/story/viewer.vue","../../src/components/story/viewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport { computed, ref } from 'vue';\n\nconst props = withDefaults(defineProps<{\n code: string\n language?: string\n}>(), {\n language: 'vue',\n});\n\nconst copied = ref(false);\n\nconst formattedCode = computed(() => props.code.trim());\n\nasync function copyToClipboard() {\n try {\n await globalThis.navigator.clipboard.writeText(formattedCode.value);\n copied.value = true;\n globalThis.setTimeout(() => {\n copied.value = false;\n }, 2000);\n } catch (error) {\n globalThis.console.error('Failed to copy:', error);\n }\n}\n</script>\n\n<template>\n <div class=\"story-code-block surface-container-high on-surface rounded-lg overflow-hidden\">\n <div class=\"flex items-center justify-between px-3 py-2 border-b border-outline-variant\">\n <span class=\"text-xs on-surface-variant\">\n {{ language || 'code' }}\n </span>\n <button\n class=\"p-1 -mr-1 surface-container-highest on-surface rounded hover:surface-container transition-colors\"\n :title=\"copied ? 'Copied!' : 'Copy code'\"\n @click=\"copyToClipboard\"\n >\n <Icon\n :icon=\"copied ? 'mdi:check' : 'mdi:content-copy'\"\n class=\"w-4 h-4\"\n />\n </button>\n </div>\n <pre class=\"overflow-x-auto p-4 text-sm font-mono\"><code>{{ formattedCode }}</code></pre>\n </div>\n</template>\n\n<style scoped>\n.story-code-block {\n font-family: 'Cascadia Code', 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;\n}\n\n.story-code-block pre {\n margin: 0;\n line-height: 1.5;\n}\n\n.story-code-block code {\n font-size: 0.875rem;\n color: inherit;\n}\n\n/* Basic syntax colors using CSS variables */\n.dark .story-code-block code {\n color: #e1e4e8;\n}\n\n.light .story-code-block code {\n color: #24292e;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport { computed, ref } from 'vue';\n\nconst props = withDefaults(defineProps<{\n code: string\n language?: string\n}>(), {\n language: 'vue',\n});\n\nconst copied = ref(false);\n\nconst formattedCode = computed(() => props.code.trim());\n\nasync function copyToClipboard() {\n try {\n await globalThis.navigator.clipboard.writeText(formattedCode.value);\n copied.value = true;\n globalThis.setTimeout(() => {\n copied.value = false;\n }, 2000);\n } catch (error) {\n globalThis.console.error('Failed to copy:', error);\n }\n}\n</script>\n\n<template>\n <div class=\"story-code-block surface-container-high on-surface rounded-lg overflow-hidden\">\n <div class=\"flex items-center justify-between px-3 py-2 border-b border-outline-variant\">\n <span class=\"text-xs on-surface-variant\">\n {{ language || 'code' }}\n </span>\n <button\n class=\"p-1 -mr-1 surface-container-highest on-surface rounded hover:surface-container transition-colors\"\n :title=\"copied ? 'Copied!' : 'Copy code'\"\n @click=\"copyToClipboard\"\n >\n <Icon\n :icon=\"copied ? 'mdi:check' : 'mdi:content-copy'\"\n class=\"w-4 h-4\"\n />\n </button>\n </div>\n <pre class=\"overflow-x-auto p-4 text-sm font-mono\"><code>{{ formattedCode }}</code></pre>\n </div>\n</template>\n\n<style scoped>\n.story-code-block {\n font-family: 'Cascadia Code', 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;\n}\n\n.story-code-block pre {\n margin: 0;\n line-height: 1.5;\n}\n\n.story-code-block code {\n font-size: 0.875rem;\n color: inherit;\n}\n\n/* Basic syntax colors using CSS variables */\n.dark .story-code-block code {\n color: #e1e4e8;\n}\n\n.light .story-code-block code {\n color: #24292e;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport { ref } from 'vue';\nimport StoryCodeBlock from './code-block.vue';\n\ninterface Props {\n code?: string | undefined\n language?: string\n title?: string | undefined\n}\n\nwithDefaults(defineProps<Props>(), {\n code: undefined,\n language: 'vue',\n title: undefined,\n});\n\nconst showCode = ref(false);\n</script>\n\n<template>\n <div class=\"story-showcase-item\">\n <div\n v-if=\"title || code\"\n class=\"mb-2 flex items-center justify-between\"\n >\n <h4\n v-if=\"title\"\n class=\"text-sm font-medium on-surface-variant\"\n >\n {{ title }}\n </h4>\n <button\n v-if=\"code\"\n class=\"ml-auto p-1.5 -mr-1.5 surface-container-highest on-surface rounded hover:surface-container transition-colors\"\n :title=\"showCode ? 'Hide code' : 'Show code'\"\n @click=\"showCode = !showCode\"\n >\n <Icon\n :icon=\"showCode ? 'mdi:code-off' : 'mdi:code-tags'\"\n class=\"w-4 h-4\"\n />\n </button>\n </div>\n\n <div class=\"story-showcase-content\">\n <slot />\n </div>\n\n <div\n v-if=\"showCode && code\"\n class=\"mt-4\"\n >\n <StoryCodeBlock\n :code=\"code\"\n :language=\"language\"\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport { ref } from 'vue';\nimport StoryCodeBlock from './code-block.vue';\n\ninterface Props {\n code?: string | undefined\n language?: string\n title?: string | undefined\n}\n\nwithDefaults(defineProps<Props>(), {\n code: undefined,\n language: 'vue',\n title: undefined,\n});\n\nconst showCode = ref(false);\n</script>\n\n<template>\n <div class=\"story-showcase-item\">\n <div\n v-if=\"title || code\"\n class=\"mb-2 flex items-center justify-between\"\n >\n <h4\n v-if=\"title\"\n class=\"text-sm font-medium on-surface-variant\"\n >\n {{ title }}\n </h4>\n <button\n v-if=\"code\"\n class=\"ml-auto p-1.5 -mr-1.5 surface-container-highest on-surface rounded hover:surface-container transition-colors\"\n :title=\"showCode ? 'Hide code' : 'Show code'\"\n @click=\"showCode = !showCode\"\n >\n <Icon\n :icon=\"showCode ? 'mdi:code-off' : 'mdi:code-tags'\"\n class=\"w-4 h-4\"\n />\n </button>\n </div>\n\n <div class=\"story-showcase-content\">\n <slot />\n </div>\n\n <div\n v-if=\"showCode && code\"\n class=\"mt-4\"\n >\n <StoryCodeBlock\n :code=\"code\"\n :language=\"language\"\n />\n </div>\n </div>\n</template>\n","// cspell:words quot\n\nimport type { Component } from 'vue';\nimport type { StoryConfig, StoryConfigOptions, StoryGroup } from './types';\n\nexport function generateCode(\n story: StoryConfig,\n options: StoryConfigOptions = {},\n): string {\n const { componentPrefix = 'P' } = options;\n\n if (!story.component) {\n return '';\n }\n\n const componentName = getComponentName(story.component, componentPrefix);\n const propsString = generatePropsString(story.props || {});\n const slotsString = story.slots ? generateSlotsString(story.slots) : '';\n\n let componentCode = slotsString ?\n `<${componentName}${propsString}>\\n${slotsString}\\n</${componentName}>` :\n `<${componentName}${propsString} />`;\n\n // If wrapper class is specified, wrap the component\n if (story.wrapperClass) {\n componentCode = `<div class=\"${story.wrapperClass}\">${componentCode}</div>`;\n }\n\n return componentCode;\n}\n\nfunction getComponentName(component: Component, prefix: string): string {\n if (typeof component === 'string') {\n return component;\n }\n\n const name = (component as Record<string, unknown>).name || (component as Record<string, unknown>).__name;\n if (!name || typeof name !== 'string') return 'Component';\n\n // Return name as-is if it already has the prefix\n return name.startsWith(prefix) ? name : `${prefix}${name}`;\n}\n\nfunction generatePropsString(props: Record<string, unknown>): string {\n const entries = Object.entries(props)\n .filter(([, value]) => value !== undefined && value !== null);\n\n if (entries.length === 0) return '';\n\n const propsArray = entries.map(([key, value]) => {\n // Boolean true: just the attribute name\n if (value === true) return key;\n\n // Boolean false: bind with false value\n if (value === false) return `:${key}=\"false\"`;\n\n // String: escape and use as attribute\n if (typeof value === 'string') {\n const escaped = value\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll('\\'', ''')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n return `${key}=\"${escaped}\"`;\n }\n\n // Number or other: bind with value\n return `:${key}=\"${JSON.stringify(value).replaceAll('\"', '"')}\"`;\n });\n\n return ' ' + propsArray.join(' ');\n}\n\nfunction generateSlotsString(slots: Record<string, (() => unknown) | string>): string {\n const slotsArray = Object.entries(slots).map(([name, content]) => {\n const slotContent = typeof content === 'function' ? 'Dynamic content' : content;\n\n return name === 'default' ? ` ${slotContent}` : ` <template #${name}>\\n ${slotContent}\\n </template>`;\n });\n\n return slotsArray.join('\\n');\n}\n\nexport function createStory(config: StoryConfig): StoryConfig {\n return config;\n}\n\nexport function createStoryGroup(\n title: string,\n description: string,\n stories: StoryConfig[],\n): StoryGroup {\n return { title, description, stories };\n}\n","<script setup lang=\"ts\">\nimport { computed, h, type VNode, type VNodeChild } from 'vue';\nimport type { StoryConfig, StoryConfigOptions } from './types';\nimport StoryShowcaseItem from './showcase-item.vue';\nimport { generateCode } from './utils';\n\ninterface Props {\n options?: StoryConfigOptions | undefined\n story: StoryConfig\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n options: undefined,\n});\n\nconst code = computed(() => generateCode(props.story, props.options));\n\n// Computed property that returns the component or render function\nconst componentToRender = computed<() => VNode>(() => {\n if (!props.story.component) {\n return () => h('div', { class: 'text-on-surface-variant' }, 'No preview available');\n }\n\n const slots: Record<string, () => VNodeChild> = {};\n\n if (props.story.slots) {\n for (const [name, content] of Object.entries(props.story.slots)) {\n slots[name] = typeof content === 'function' ? content : () => content;\n }\n }\n\n const component = () => h(props.story.component!, props.story.props || {}, slots);\n\n // If wrapper class is specified, wrap the component\n if (props.story.wrapperClass) {\n return () => h('div', { class: props.story.wrapperClass }, [component()]);\n }\n\n return component;\n});\n</script>\n\n<template>\n <StoryShowcaseItem\n :title=\"story.title\"\n :code=\"code\"\n language=\"vue\"\n >\n <component :is=\"componentToRender\" />\n </StoryShowcaseItem>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, h, type VNode, type VNodeChild } from 'vue';\nimport type { StoryConfig, StoryConfigOptions } from './types';\nimport StoryShowcaseItem from './showcase-item.vue';\nimport { generateCode } from './utils';\n\ninterface Props {\n options?: StoryConfigOptions | undefined\n story: StoryConfig\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n options: undefined,\n});\n\nconst code = computed(() => generateCode(props.story, props.options));\n\n// Computed property that returns the component or render function\nconst componentToRender = computed<() => VNode>(() => {\n if (!props.story.component) {\n return () => h('div', { class: 'text-on-surface-variant' }, 'No preview available');\n }\n\n const slots: Record<string, () => VNodeChild> = {};\n\n if (props.story.slots) {\n for (const [name, content] of Object.entries(props.story.slots)) {\n slots[name] = typeof content === 'function' ? content : () => content;\n }\n }\n\n const component = () => h(props.story.component!, props.story.props || {}, slots);\n\n // If wrapper class is specified, wrap the component\n if (props.story.wrapperClass) {\n return () => h('div', { class: props.story.wrapperClass }, [component()]);\n }\n\n return component;\n});\n</script>\n\n<template>\n <StoryShowcaseItem\n :title=\"story.title\"\n :code=\"code\"\n language=\"vue\"\n >\n <component :is=\"componentToRender\" />\n </StoryShowcaseItem>\n</template>\n","<script setup lang=\"ts\">\ninterface Props {\n description?: string\n title: string\n}\n\ndefineProps<Props>();\n</script>\n\n<template>\n <section class=\"mb-8\">\n <header class=\"mb-4\">\n <h2 class=\"text-2xl font-bold text-on-surface\">\n {{ title }}\n </h2>\n <p\n v-if=\"description\"\n class=\"text-on-surface-variant mt-1\"\n >\n {{ description }}\n </p>\n </header>\n <div class=\"space-y-4\">\n <slot />\n </div>\n </section>\n</template>\n","<script setup lang=\"ts\">\ninterface Props {\n description?: string\n title: string\n}\n\ndefineProps<Props>();\n</script>\n\n<template>\n <section class=\"mb-8\">\n <header class=\"mb-4\">\n <h2 class=\"text-2xl font-bold text-on-surface\">\n {{ title }}\n </h2>\n <p\n v-if=\"description\"\n class=\"text-on-surface-variant mt-1\"\n >\n {{ description }}\n </p>\n </header>\n <div class=\"space-y-4\">\n <slot />\n </div>\n </section>\n</template>\n","<script setup lang=\"ts\">\ninterface Props {\n center?: boolean\n gap?: 'base' | 'lg' | 'sm' | 'xl' | 'xs'\n wrap?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n gap: 'base',\n wrap: true,\n center: false,\n});\n</script>\n\n<template>\n <div\n :class=\"[\n 'flex',\n {\n 'flex-wrap': wrap,\n 'items-center': center,\n 'gap-2': gap === 'xs',\n 'gap-3': gap === 'sm',\n 'gap-4': gap === 'base',\n 'gap-6': gap === 'lg',\n 'gap-8': gap === 'xl',\n },\n ]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\ninterface Props {\n center?: boolean\n gap?: 'base' | 'lg' | 'sm' | 'xl' | 'xs'\n wrap?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n gap: 'base',\n wrap: true,\n center: false,\n});\n</script>\n\n<template>\n <div\n :class=\"[\n 'flex',\n {\n 'flex-wrap': wrap,\n 'items-center': center,\n 'gap-2': gap === 'xs',\n 'gap-3': gap === 'sm',\n 'gap-4': gap === 'base',\n 'gap-6': gap === 'lg',\n 'gap-8': gap === 'xl',\n },\n ]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { StoryConfigOptions, StoryGroup } from './types';\nimport StoryRenderer from './renderer.vue';\nimport StorySection from './section.vue';\nimport StoryShowcase from './showcase.vue';\n\ninterface Props {\n group: StoryGroup\n options?: StoryConfigOptions | undefined\n showcaseProps?: Record<string, unknown>\n}\n\nwithDefaults(defineProps<Props>(), {\n options: undefined,\n showcaseProps: () => ({ gap: 'lg' }),\n});\n</script>\n\n<template>\n <StorySection\n :title=\"group.title\"\n :description=\"group.description\"\n >\n <StoryShowcase v-bind=\"showcaseProps\">\n <StoryRenderer\n v-for=\"(story, index) in group.stories\"\n :key=\"`${story.title}-${index}`\"\n :story=\"story\"\n :options=\"options\"\n />\n </StoryShowcase>\n </StorySection>\n</template>\n","<script setup lang=\"ts\">\nimport type { StoryConfigOptions, StoryGroup } from './types';\nimport StoryRenderer from './renderer.vue';\nimport StorySection from './section.vue';\nimport StoryShowcase from './showcase.vue';\n\ninterface Props {\n group: StoryGroup\n options?: StoryConfigOptions | undefined\n showcaseProps?: Record<string, unknown>\n}\n\nwithDefaults(defineProps<Props>(), {\n options: undefined,\n showcaseProps: () => ({ gap: 'lg' }),\n});\n</script>\n\n<template>\n <StorySection\n :title=\"group.title\"\n :description=\"group.description\"\n >\n <StoryShowcase v-bind=\"showcaseProps\">\n <StoryRenderer\n v-for=\"(story, index) in group.stories\"\n :key=\"`${story.title}-${index}`\"\n :story=\"story\"\n :options=\"options\"\n />\n </StoryShowcase>\n </StorySection>\n</template>\n","<script setup lang=\"ts\">\nimport type { RouteLocationNormalizedLoaded, Router } from 'vue-router';\nimport { type Component, computed, onMounted, onUnmounted, provide, ref, watch } from 'vue';\n\nexport interface StoryDefinition {\n component: Component\n description?: string\n name: string\n}\n\ninterface Props {\n defaultStory?: string\n stories: StoryDefinition[]\n useRouter?: {\n route: RouteLocationNormalizedLoaded\n router: Router\n }\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n defaultStory: undefined,\n useRouter: undefined,\n});\n\n// Create URL-safe slugs for each story\nconst createSlug = (name: string) => name.toLowerCase().replaceAll(/\\s+/g, '-');\n\n// Get story name from slug\nconst getStoryFromSlug = (slug: string) => {\n const story = props.stories.find((s) => createSlug(s.name) === slug);\n return story?.name || '';\n};\n\n// Navigation abstraction\nconst navigation = computed(() =>\n props.useRouter ?\n {\n // Vue Router navigation\n getCurrentStory: () => {\n const storyParam = props.useRouter!.route.query.story as string;\n if (storyParam) {\n const storyName = getStoryFromSlug(storyParam);\n if (storyName) return storyName;\n }\n return props.defaultStory || props.stories[0]?.name || '';\n },\n setStory: (storyName: string) => {\n const slug = createSlug(storyName);\n props.useRouter!.router.push({\n query: { ...props.useRouter!.route.query, story: slug },\n });\n },\n init: () => {\n if (!props.useRouter!.route.query.story && currentStory.value) {\n const slug = createSlug(currentStory.value.name);\n props.useRouter!.router.replace({\n query: { ...props.useRouter!.route.query, story: slug },\n });\n }\n },\n } :\n {\n // Hash-based navigation\n getCurrentStory: () => {\n if (globalThis.location !== undefined) {\n const hash = globalThis.location.hash.slice(1);\n if (hash) {\n const storyName = getStoryFromSlug(hash);\n if (storyName) return storyName;\n }\n }\n return props.defaultStory || props.stories[0]?.name || '';\n },\n setStory: (storyName: string) => {\n if (globalThis.location !== undefined) {\n globalThis.location.hash = createSlug(storyName);\n }\n },\n init: () => {\n if (globalThis.location !== undefined && !globalThis.location.hash && currentStory.value) {\n globalThis.location.hash = createSlug(currentStory.value.name);\n }\n },\n },\n);\n\n// Determine initial story\nconst getInitialStoryName = () => {\n // In test environment or when no hash, use defaultStory if provided\n if (globalThis.location === undefined || !globalThis.location.hash) {\n return props.defaultStory || props.stories[0]?.name || '';\n }\n // Otherwise use the navigation logic\n return navigation.value.getCurrentStory();\n};\n\n// Current story state\nconst currentStoryName = ref<string>(getInitialStoryName());\n\nconst currentStory = computed(() => {\n return props.stories.find((s) => s.name === currentStoryName.value);\n});\n\n// Update current story when props change\nwatch(() => [props.stories, props.defaultStory], () => {\n const newStory = navigation.value.getCurrentStory();\n if (newStory !== currentStoryName.value) {\n currentStoryName.value = newStory;\n }\n});\n\n// Update URL when story changes\nconst selectStory = (storyName: string) => {\n currentStoryName.value = storyName;\n navigation.value.setStory(storyName);\n};\n\n// Handle navigation changes\nlet hashChangeListener: (() => void) | undefined;\n\nif (props.useRouter) {\n // Watch route changes for Vue Router\n watch(() => props.useRouter!.route.query.story, (newStory) => {\n if (newStory) {\n const storyName = getStoryFromSlug(newStory as string);\n if (storyName && storyName !== currentStoryName.value) {\n currentStoryName.value = storyName;\n }\n }\n });\n} else {\n // Setup hash change listener\n onMounted(() => {\n hashChangeListener = () => {\n const newStoryName = navigation.value.getCurrentStory();\n if (newStoryName !== currentStoryName.value) {\n currentStoryName.value = newStoryName;\n }\n };\n if (typeof globalThis.addEventListener === 'function') {\n globalThis.addEventListener('hashchange', hashChangeListener);\n }\n });\n\n onUnmounted(() => {\n if (hashChangeListener && typeof globalThis.removeEventListener === 'function') {\n globalThis.removeEventListener('hashchange', hashChangeListener);\n }\n });\n}\n\n// Initialize navigation on mount\nonMounted(() => {\n // Only initialize navigation if we're not in a test environment\n // or if we have a router (which handles its own navigation)\n if (props.useRouter || globalThis.location !== undefined) {\n navigation.value.init();\n }\n});\n\n// Mobile menu state\nconst isMobileMenuOpen = ref(false);\n\n// Provide story context for nested components\nprovide('storyViewer', {\n currentStory: currentStoryName,\n});\n</script>\n\n<template>\n <div class=\"flex flex-col min-h-screen\">\n <!-- Mobile Header -->\n <div class=\"lg:hidden surface-container-high shadow-z1 sticky top-0 z-20\">\n <div class=\"p-4 flex items-center justify-between\">\n <h1 class=\"text-lg font-bold\">\n <slot name=\"title\">\n Component Stories\n </slot>\n </h1>\n <button\n class=\"p-2 rounded-md hover:bg-surface-container-highest\"\n :aria-label=\"isMobileMenuOpen ? 'Close menu' : 'Open menu'\"\n @click=\"isMobileMenuOpen = !isMobileMenuOpen\"\n >\n <svg\n class=\"w-6 h-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n v-if=\"!isMobileMenuOpen\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 6h16M4 12h16M4 18h16\"\n />\n <path\n v-else\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Mobile Menu Overlay -->\n <div\n v-if=\"isMobileMenuOpen\"\n class=\"lg:hidden fixed inset-0 z-10 bg-scrim/50\"\n @click=\"isMobileMenuOpen = false\"\n />\n\n <!-- Main Layout -->\n <div class=\"flex flex-1\">\n <!-- Sidebar Navigation -->\n <div\n :class=\"[\n 'fixed lg:static inset-y-0 left-0 z-20 w-64',\n 'surface-container-high shadow-z2 lg:shadow-z1',\n 'transform transition-transform duration-200 lg:translate-x-0',\n 'flex flex-col h-full lg:h-auto',\n isMobileMenuOpen ? 'translate-x-0' : '-translate-x-full',\n ]\"\n >\n <div class=\"hidden lg:block p-4 border-b border-outline-variant\">\n <h1 class=\"text-xl font-bold\">\n <slot name=\"title\">\n Component Stories\n </slot>\n </h1>\n </div>\n\n <!-- Story List -->\n <nav class=\"flex-1 p-2 overflow-y-auto\">\n <button\n v-for=\"story in stories\"\n :key=\"story.name\"\n :class=\"[\n 'w-full text-left px-4 py-2 mb-1 rounded-md transition-colors',\n 'text-sm font-medium',\n currentStoryName === story.name\n ? 'bg-primary text-on-primary'\n : 'hover:bg-surface-container-highest text-on-surface'\n ]\"\n @click=\"selectStory(story.name); isMobileMenuOpen = false\"\n >\n {{ story.name }}\n </button>\n </nav>\n </div>\n\n <!-- Main Content -->\n <div class=\"flex-1 flex flex-col lg:ml-0\">\n <!-- Story Header -->\n <div\n v-if=\"currentStory\"\n class=\"surface-container p-4 lg:p-6 border-b border-outline-variant\"\n >\n <h2 class=\"text-xl lg:text-2xl font-bold mb-1\">\n {{ currentStory.name }}\n </h2>\n <p\n v-if=\"currentStory.description\"\n class=\"text-on-surface-variant text-sm lg:text-base\"\n >\n {{ currentStory.description }}\n </p>\n </div>\n\n <!-- Story Content -->\n <div class=\"flex-1 surface overflow-y-auto\">\n <div class=\"container m-auto max-w-6xl p-4 lg:p-6\">\n <slot\n name=\"story\"\n :story=\"currentStory\"\n >\n <component\n :is=\"currentStory?.component\"\n v-if=\"currentStory\"\n />\n </slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { RouteLocationNormalizedLoaded, Router } from 'vue-router';\nimport { type Component, computed, onMounted, onUnmounted, provide, ref, watch } from 'vue';\n\nexport interface StoryDefinition {\n component: Component\n description?: string\n name: string\n}\n\ninterface Props {\n defaultStory?: string\n stories: StoryDefinition[]\n useRouter?: {\n route: RouteLocationNormalizedLoaded\n router: Router\n }\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n defaultStory: undefined,\n useRouter: undefined,\n});\n\n// Create URL-safe slugs for each story\nconst createSlug = (name: string) => name.toLowerCase().replaceAll(/\\s+/g, '-');\n\n// Get story name from slug\nconst getStoryFromSlug = (slug: string) => {\n const story = props.stories.find((s) => createSlug(s.name) === slug);\n return story?.name || '';\n};\n\n// Navigation abstraction\nconst navigation = computed(() =>\n props.useRouter ?\n {\n // Vue Router navigation\n getCurrentStory: () => {\n const storyParam = props.useRouter!.route.query.story as string;\n if (storyParam) {\n const storyName = getStoryFromSlug(storyParam);\n if (storyName) return storyName;\n }\n return props.defaultStory || props.stories[0]?.name || '';\n },\n setStory: (storyName: string) => {\n const slug = createSlug(storyName);\n props.useRouter!.router.push({\n query: { ...props.useRouter!.route.query, story: slug },\n });\n },\n init: () => {\n if (!props.useRouter!.route.query.story && currentStory.value) {\n const slug = createSlug(currentStory.value.name);\n props.useRouter!.router.replace({\n query: { ...props.useRouter!.route.query, story: slug },\n });\n }\n },\n } :\n {\n // Hash-based navigation\n getCurrentStory: () => {\n if (globalThis.location !== undefined) {\n const hash = globalThis.location.hash.slice(1);\n if (hash) {\n const storyName = getStoryFromSlug(hash);\n if (storyName) return storyName;\n }\n }\n return props.defaultStory || props.stories[0]?.name || '';\n },\n setStory: (storyName: string) => {\n if (globalThis.location !== undefined) {\n globalThis.location.hash = createSlug(storyName);\n }\n },\n init: () => {\n if (globalThis.location !== undefined && !globalThis.location.hash && currentStory.value) {\n globalThis.location.hash = createSlug(currentStory.value.name);\n }\n },\n },\n);\n\n// Determine initial story\nconst getInitialStoryName = () => {\n // In test environment or when no hash, use defaultStory if provided\n if (globalThis.location === undefined || !globalThis.location.hash) {\n return props.defaultStory || props.stories[0]?.name || '';\n }\n // Otherwise use the navigation logic\n return navigation.value.getCurrentStory();\n};\n\n// Current story state\nconst currentStoryName = ref<string>(getInitialStoryName());\n\nconst currentStory = computed(() => {\n return props.stories.find((s) => s.name === currentStoryName.value);\n});\n\n// Update current story when props change\nwatch(() => [props.stories, props.defaultStory], () => {\n const newStory = navigation.value.getCurrentStory();\n if (newStory !== currentStoryName.value) {\n currentStoryName.value = newStory;\n }\n});\n\n// Update URL when story changes\nconst selectStory = (storyName: string) => {\n currentStoryName.value = storyName;\n navigation.value.setStory(storyName);\n};\n\n// Handle navigation changes\nlet hashChangeListener: (() => void) | undefined;\n\nif (props.useRouter) {\n // Watch route changes for Vue Router\n watch(() => props.useRouter!.route.query.story, (newStory) => {\n if (newStory) {\n const storyName = getStoryFromSlug(newStory as string);\n if (storyName && storyName !== currentStoryName.value) {\n currentStoryName.value = storyName;\n }\n }\n });\n} else {\n // Setup hash change listener\n onMounted(() => {\n hashChangeListener = () => {\n const newStoryName = navigation.value.getCurrentStory();\n if (newStoryName !== currentStoryName.value) {\n currentStoryName.value = newStoryName;\n }\n };\n if (typeof globalThis.addEventListener === 'function') {\n globalThis.addEventListener('hashchange', hashChangeListener);\n }\n });\n\n onUnmounted(() => {\n if (hashChangeListener && typeof globalThis.removeEventListener === 'function') {\n globalThis.removeEventListener('hashchange', hashChangeListener);\n }\n });\n}\n\n// Initialize navigation on mount\nonMounted(() => {\n // Only initialize navigation if we're not in a test environment\n // or if we have a router (which handles its own navigation)\n if (props.useRouter || globalThis.location !== undefined) {\n navigation.value.init();\n }\n});\n\n// Mobile menu state\nconst isMobileMenuOpen = ref(false);\n\n// Provide story context for nested components\nprovide('storyViewer', {\n currentStory: currentStoryName,\n});\n</script>\n\n<template>\n <div class=\"flex flex-col min-h-screen\">\n <!-- Mobile Header -->\n <div class=\"lg:hidden surface-container-high shadow-z1 sticky top-0 z-20\">\n <div class=\"p-4 flex items-center justify-between\">\n <h1 class=\"text-lg font-bold\">\n <slot name=\"title\">\n Component Stories\n </slot>\n </h1>\n <button\n class=\"p-2 rounded-md hover:bg-surface-container-highest\"\n :aria-label=\"isMobileMenuOpen ? 'Close menu' : 'Open menu'\"\n @click=\"isMobileMenuOpen = !isMobileMenuOpen\"\n >\n <svg\n class=\"w-6 h-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n v-if=\"!isMobileMenuOpen\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 6h16M4 12h16M4 18h16\"\n />\n <path\n v-else\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Mobile Menu Overlay -->\n <div\n v-if=\"isMobileMenuOpen\"\n class=\"lg:hidden fixed inset-0 z-10 bg-scrim/50\"\n @click=\"isMobileMenuOpen = false\"\n />\n\n <!-- Main Layout -->\n <div class=\"flex flex-1\">\n <!-- Sidebar Navigation -->\n <div\n :class=\"[\n 'fixed lg:static inset-y-0 left-0 z-20 w-64',\n 'surface-container-high shadow-z2 lg:shadow-z1',\n 'transform transition-transform duration-200 lg:translate-x-0',\n 'flex flex-col h-full lg:h-auto',\n isMobileMenuOpen ? 'translate-x-0' : '-translate-x-full',\n ]\"\n >\n <div class=\"hidden lg:block p-4 border-b border-outline-variant\">\n <h1 class=\"text-xl font-bold\">\n <slot name=\"title\">\n Component Stories\n </slot>\n </h1>\n </div>\n\n <!-- Story List -->\n <nav class=\"flex-1 p-2 overflow-y-auto\">\n <button\n v-for=\"story in stories\"\n :key=\"story.name\"\n :class=\"[\n 'w-full text-left px-4 py-2 mb-1 rounded-md transition-colors',\n 'text-sm font-medium',\n currentStoryName === story.name\n ? 'bg-primary text-on-primary'\n : 'hover:bg-surface-container-highest text-on-surface'\n ]\"\n @click=\"selectStory(story.name); isMobileMenuOpen = false\"\n >\n {{ story.name }}\n </button>\n </nav>\n </div>\n\n <!-- Main Content -->\n <div class=\"flex-1 flex flex-col lg:ml-0\">\n <!-- Story Header -->\n <div\n v-if=\"currentStory\"\n class=\"surface-container p-4 lg:p-6 border-b border-outline-variant\"\n >\n <h2 class=\"text-xl lg:text-2xl font-bold mb-1\">\n {{ currentStory.name }}\n </h2>\n <p\n v-if=\"currentStory.description\"\n class=\"text-on-surface-variant text-sm lg:text-base\"\n >\n {{ currentStory.description }}\n </p>\n </div>\n\n <!-- Story Content -->\n <div class=\"flex-1 surface overflow-y-auto\">\n <div class=\"container m-auto max-w-6xl p-4 lg:p-6\">\n <slot\n name=\"story\"\n :story=\"currentStory\"\n >\n <component\n :is=\"currentStory?.component\"\n v-if=\"currentStory\"\n />\n </slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;EAIA,SAAM;EAON,MAAM,QAAA;EAEN,MAAM,SAAA,IAAA,KAAgB;EAEtB,MAAA,gBAAe,eAAkB,MAAA,KAAA,KAAA,CAAA;iBAC3B,kBAAA;OACF;IACA,MAAA,WAAe,UAAA,UAAA,UAAA,cAAA,KAAA;IACf,OAAA,QAAW;eACF,iBAAQ;KACjB,OAAO,QAAA;IACT,GAAA,GAAA;YACE,OAAW;IACb,WAAA,QAAA,MAAA,mBAAA,KAAA;GACF;;;;;;;;;;;;;;;;;;;;;;;;uBCoBS,OAAM,8EAAA;;;qBAfX,EAAA,OAcM,wCAAA;SAbJ,cAAA,MAAA,QAAA,QAEO,QAAA,OAAA,UADF;QAKF,UAAK,GAAA,mBAAA,OAAA,cAAA,CAAA,mBAAA,OAAA,cAAA,CAAA,mBAAA,QAAA,cAAA,gBAAA,OAAA,YAAA,MAAA,GAAA,CAAA,GAAA,mBAAA,UAAA;EAAA,OAAA;EAEN,OAAA,OAAA,SAGE,YAAA;EAAA,SAAA,OADM;IAAS,CAAA,YAAA,OAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBCxBJ;;;;;;;;;;;;;;MCOf,eAAM,EAAA,OAAA,sBAAA;MAAA,eAAA;;;;MAIE,eAAA;;;;;MAuBR,eAAY,EAAA,OAAA,yBAAA;MAAA,eAAA;;;;uBA7Bd,MAAA,QAAA,QAqBM,QArBN,OAAA,UAqBM;QAAA,UAhBI,GAAA,mBAAK,OAAA,cAAA;SAQL,SAAA,OAAA,QAAA,UAAA,GAAA,mBAAA,OAAA,cAAA,CAAA,OAAA,SAAA,UAAA,GAAA,mBAAA,MAAA,cAAA,gBAAA,OAAA,KAAA,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,GAAA,OAAA,QAAA,UAAA,GAAA,mBAAA,UAAA;GACL,KAAA;GAAK,OAAA;GAEN,OAAA,OAAA,WAGE,cAAA;GAAA,SAAA,OADM,OAAS,OAAA,MAAA,WAAA,OAAA,WAAA,CAAA,OAAA;KAAA,CAAA,YAAA,OAAA,SAAA;;;EAMX,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,GAAA,GAAA,YAAA,KAIF,mBAAQ,QAAI,IAAI,CAAA,CAAA,KAAA,mBAAA,QAAA,IAAA;qBAMpB,OAAA,cAAA,CAAA,WAFO,KAAA,QAAA,SAAI,CAAA,CAAA;SACQ,YAAA,OAAA,QAAA,UAAA,GAAA,mBAAA,OAAA,cAAA,CAAA,YAAA,OAAA,mBAAA;;;;;;;SC9CjB,aAAA,OAAkB,UAAQ,CAAA,GAAA;CAElC,MAAK,EAAA,kBACH,QAAO;CAGT,IAAA,CAAA,MAAM,WAAgB,OAAA;CACtB,MAAM,gBAAc,iBAAA,MAAoB,WAAgB,eAAC;CACzD,MAAM,cAAc,oBAAc,MAAA,SAAoB,CAAA,CAAA;CAEtD,MAAI,cAAgB,MAAA,QAClB,oBAAoB,MAAA,KAAA,IAAY;CAIlC,IAAI,gBAAM,cACR,IAAA,gBAAgB,YAAqB,KAAA,YAAiB,MAAA,cAAc,KAAA,IAAA,gBAAA,YAAA;CAGtE,IAAA,MAAO,cAAA,gBAAA,eAAA,MAAA,aAAA,IAAA,cAAA;CACT,OAAA;AAEA;SACM,iBAAqB,WACvB,QAAO;CAGT,IAAA,OAAM,cAA8C,UAAS,OAAsC;CACnG,MAAK,OAAQ,UAAO,QAAS,UAAU;CAGvC,IAAA,CAAA,QAAY,OAAA,SAAiB,UAAI,OAAU;CAC7C,OAAA,KAAA,WAAA,MAAA,IAAA,OAAA,GAAA,SAAA;AAEA;SACQ,oBAAiB,OAAQ;CAG/B,MAAI,UAAQ,OAAW,QAAG,KAAO,EAAA,QAAA,GAAA,WAAA,UAAA,KAAA,KAAA,UAAA,IAAA;CAwBjC,IAAA,QAAO,WAtBoB,GAAK,OAAM;QAEhC,MAAA,QAAgB,KAAA,CAAA,KAAO,WAAA;EAG3B,IAAI,UAAU,MAAA,OAAO;EAGrB,IAAI,UAAO,OAAU,OAAA,IAOnB,IAAA;EAIF,IAAA,OAAW,UAAQ,UAAK,OAAU,GAAO,IAAA,IAAA,MAAW,WAAa,KAAE,OAAA,EAAA,WAAA,MAAA,QAAA,EAAA,WAAA,KAAA,OAAA,EAAA,WAAA,KAAA,MAAA,EAAA,WAAA,KAAA,MAAA,EAAA;EAG/C,OAAO,IAAG,IAAA,IAAA,KAAA,UAAA,KAAA,EAAA,WAAA,MAAA,QAAA,EAAA;CAClC,CAAA,EAAA,KAAA,GAAA;AAEA;SACqB,oBAAoB,OAAQ;QACvC,OAAA,QAAc,KAAA,EAAO,KAAA,CAAA,MAAY,aAAa;EAEpD,MAAA,cAAgB,OAAA,YAAiB,aAAgB,oBAAqB;EAGxD,OAAO,SAAI,YAAA,KAAA,gBAAA,gBAAA,KAAA,SAAA,YAAA;CAC7B,CAAA,EAAA,KAAA,IAAA;AAEA;SACS,YAAA,QAAA;CACT,OAAA;AAEA;SAKS,iBAAA,OAAA,aAAA,SAAA;QAAE;EAAO;EAAa;EAAQ;CACvC;;;;;;;;;;;;;;;;ECnFA,SAAM;;;;wBAOoB,aAA4B,MAAA,OAAA,MAAA,OAAA,CAAA;sBACnC,eACf;IAGF,IAAA,CAAA,MAAM,MAA2C,WAAA,aAAA,EAAA,OAAA,EAAA,OAAA,0BAAA,GAAA,sBAAA;IAEjD,MAAI,QAAM,CAAA;IAMV,IAAA,MAAM,MAAA,OAAA,KAAoB,MAAM,CAAA,MAAM,YAAY,OAAM,QAAM,MAAa,MAAK,KAAA,GAAA,MAAA,QAAA,OAAA,YAAA,aAAA,gBAAA;IAGhF,MAAI,kBAAY,EAAA,MACd,MAAA,WAAe,MAAS,MAAO,SAAM,CAAA,GAAM,KAAA;IAG7C,IAAA,MAAO,MAAA,cAAA,aAAA,EAAA,OAAA,EAAA,OAAA,MAAA,MAAA,aAAA,GAAA,CAAA,UAAA,CAAA,CAAA;IACT,OAAA;;;;;;;;;;;SCMW,cAAI,MAAA,QAAA,QAAA,QAAA,OAAA,UAAA;QACX,UAAS,GAAA,YAAK,OAAA,sBAAA;EAAA,OAAA,OAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ME7BV,eAAM,EAAA,OAAA,qCAAA;MAAA,eAAA;;;;qBANV,EAAA,OAUS,YAVT;SACE,cAAA,MAAA,QAAA,QAEK,QAAA,OAAA,UADA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBEGqG,GAAA,mBAAG,OAAA,EAAA,OAAA,eAAA,CAAA,QAAA;EAAA,aAAA,OAA4B;EAAG,gBAA4B,OAAA;EAAG,SAA8B,OAAA,QAAG;EAAA,SAA4B,OAAA,QAAG;EAAA,SAAA,OAAA,QAAA;;EAa7O,SAAA,OAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SERC,cAAa,MAAA,QAAM,QAAW,QAAA,OAAA,UAAA;QAAA,UAAA,GAAA,YAAA,OAAA,iBAAA;sBASf;EAAA,aAAA,OAAA,MAAA;;WALJ,cAAA,CAAA,YACC,OAAM,kBAAA,eAAc,mBAAA,OAAA,aAAA,CAAA,GAAA;YACvB,cAAO,EAAA,UAAA,IAAA,GAAA,mBAAA,UAAA,MAAA,WAAA,OAAA,MAAA,UAAA,OAAA,UAAA;WACZ,UAAS,GAAA,YAAO,OAAA,kBAAA;KAAA,KAAA,GAAA,MAAA,MAAA,GAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECTzB,SAAM;EAMN,MAAM,QAAA;EAGN,MAAM,cAAA,SAAoB,KAAA,YAAiB,EAAA,WAAA,QAAA,GAAA;QAEzC,oBAD4B,SAAY;GAE1C,OAAA,MAAA,QAAA,MAAA,MAAA,WAAA,EAAA,IAAA,MAAA,IAAA,GAAA,QAAA;EAGA;QAIM,aAAA,eAAuB,MAAA,YAAA;0BACF;IACnB,MAAI,aAAY,MAAA,UAAA,MAAA,MAAA;QACd,YAAM;KACN,MAAI,YAAW,iBAAO,UAAA;KACxB,IAAA,WAAA,OAAA;IACA;IACF,OAAA,MAAA,gBAAA,MAAA,QAAA,IAAA,QAAA;GACA;cACQ,cAAkB;IACxB,MAAM,OAAA,WAAkB,SACtB;UAAY,UAAM,OAAW,KAAM,EAAA,OAAA;KAAO,GAAA,MAAO,UAAA,MAAA;KAAK,OACvD;IACH,EAAA,CAAA;GACA;eACa;QACT,CAAA,MAAM,UAAO,MAAW,MAAA,SAAa,aAAU,OAAA;KAC/C,MAAM,OAAA,WAAkB,aACtB,MAAO,IAAA;WAAK,UAAM,OAAW,QAAM,EAAA,OAAA;MAAO,GAAA,MAAO,UAAA,MAAA;MAAK,OACvD;KACH,EAAA,CAAA;IACF;GACF;MAGE;0BACiB;QACb,WAAa,aAAW,KAAA,GAAS;KACjC,MAAI,OAAM,WAAA,SAAA,KAAA,MAAA,CAAA;SACR,MAAM;MACN,MAAI,YAAW,iBAAO,IAAA;MACxB,IAAA,WAAA,OAAA;KACF;IACA;IACF,OAAA,MAAA,gBAAA,MAAA,QAAA,IAAA,QAAA;GACA;cACM,cAAW;IAGjB,IAAA,WAAA,aAAA,KAAA,GAAA,WAAA,SAAA,OAAA,WAAA,SAAA;GACA;eACM;IAGN,IAAA,WAAA,aAAA,KAAA,KAAA,CAAA,WAAA,SAAA,QAAA,aAAA,OAAA,WAAA,SAAA,OAAA,WAAA,aAAA,MAAA,IAAA;GAEN;EAGA,CAAA;QAEM,4BAAwB;GAI5B,IAAA,WAAO,aAAiB,KAAA,KAAA,CAAA,WAAgB,SAAA,MAAA,OAAA,MAAA,gBAAA,MAAA,QAAA,IAAA,QAAA;GAC1C,OAAA,WAAA,MAAA,gBAAA;EAGA;EAEA,MAAM,mBAAe,IAAA,oBAAe,CAAA;QAClC,eAAa,eAAsB;GACpC,OAAA,MAAA,QAAA,MAAA,MAAA,EAAA,SAAA,iBAAA,KAAA;EAGD,CAAA;cACQ,CAAA,MAAW,SAAA,MAAW,YAAM,SAAgB;GAClD,MAAI,WAAa,WAAA,MAAiB,gBAChC;GAEH,IAAA,aAAA,iBAAA,OAAA,iBAAA,QAAA;EAGD,CAAA;QACE,eAAiB,cAAQ;GACzB,iBAAiB,QAAA;GACnB,WAAA,MAAA,SAAA,SAAA;EAGA;EAEA,IAAI;MAGA,MAAI,WAAU,YAAA,MAAA,UAAA,MAAA,MAAA,QAAA,aAAA;OACZ,UAAM;IACN,MAAI,YAAa,iBAAc,QAAA;IAGjC,IAAA,aAAA,cAAA,iBAAA,OAAA,iBAAA,QAAA;GACD;;OAGD;mBACE;+BACuB;KACrB,MAAI,eAAiB,WAAA,MAAiB,gBACpC;KAEJ,IAAA,iBAAA,iBAAA,OAAA,iBAAA,QAAA;IACA;IAGD,IAAA,OAAA,WAAA,qBAAA,YAAA,WAAA,iBAAA,cAAA,kBAAA;GAED,CAAA;qBACM;IAGL,IAAA,sBAAA,OAAA,WAAA,wBAAA,YAAA,WAAA,oBAAA,cAAA,kBAAA;GACH,CAAA;EAGA;kBAGY;GAGX,IAAA,MAAA,aAAA,WAAA,aAAA,KAAA,GAAA,WAAA,MAAA,KAAA;EAGD,CAAA;EAGA,MAAA,mBACE,IAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;qBCSU,OAAM,6BAAA;;;MAWN,aAAe,EAAA,OAAA,oBAAA;MACX,aAAO,CAAA,YAAA;MACX,aAAM;CACN,OAAA;CAAA,MAAA;;;;MAKE,aAAA;CACA,KAAA;CACA,kBAAA;CAAE,mBAAA;;;;MAKF,aAAA;CACA,KAAA;CACA,kBAAA;CAAE,mBAAA;;;;4BAmCH,cAAM;;sBAmBR,OAAM,oBAAA;;;MAIP,cAAM,EAAA,OAAA,+BAAA;MAAA,cAAA;;;;MAOJ,cAAM,EAAA,OAAA,qCAAA;MAAA,cAAA;;;;;oBAhGd,EAAA,OAAA,wCAAsB;SACtB,YAmCM,MAAA,QAAA,QAAA,QAAA,OAAA,UAAA;QAAA,UAAA,GAlCJ,mBAAA,OAAA,YAAA;EAAA,mBACE,iBAIK;qBAIG,OAAA,YAAA,CAAA,mBAAA,OAAA,YAAA,CAAA,mBAAA,MAAA,YAAA,CAAA,WAAA,KAAA,QAAA,SAAA,CAAA,SAAA,CAAA,OAAA,OAAA,OAAA,KAAA,gBAAA,uBAAA,EAAA,EAAA,CAAA,CAAA,CAAA,GAAA,mBAAA,UAAA;GAAA,OAAA;wBAEN,mBAoBM,eAAA;GAAA,SAAA,OAAA,OAAA,OAAA,MAdJ,WAME,OAAA,mBANF,CAAA,OAAA;EAqBA,GAAA,EAAA,UAAA,GAAA,mBADR,OAIE,YAAA,CAAA,CAAA,OAAA,oBAAA,UAAA,GAAA,mBAAA,QAAA,UAAA,MAAA,UAAA,GAAA,mBAAA,QAAA,UAAA,EAAA,CAAA,EAAA,GAAA,GAAA,UAAA,CAAA,CAAA,CAAA,CAAA;EAAA,mBAAA,uBAFM;SACL,oBAAA,UAAA,GAAA,mBAAA,OAAA;GAAA,KAAA;;GAGH,SACA,OAAA,OAAA,OAuEM,MAvEN,WAAA,OAAA,mBAAA;EAAA,CAAA,KAAA,mBACE,QAAA,IAAA;EAAA,mBACA,eAkCM;qBAAA,OAjCE,YAAA;GAAA,mBAAA,sBAAA;;;IAAuP;IAAA;;IAQ7P,OAAA,mBAAA,kBAAA;;IASA,mBAAA,OAAA,aACE,CAAA,mBAAA,MAAA,aAAA,CAAA,WAAA,KAAA,QAAA,SAAA,CAAA,SAAA,CAAA,OAAA,OAAA,OAAA,KAAA,gBAAA,uBAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA;IAAA,mBAAA,cAAA;uBAGQ,OAAA,aAAA,EAAA,UAAA,IAAA,GAAA,mBAAA,UAAA,MAAA,WAAA,OAAA,UAAA,UAAA;YAAA,UAAA,GAAA,mBAAA,UAAA;;aAAqI,eAAA;OAAA;;OAO1I,OAAA,qBAAA,MAAA,OAAA,+BAAA;;;;;;wBAOP,MAAA,IAAA,GAAA,IAAA,WAAA;IACA,CAAA,GAAA,GAAA,EAAA,CAAA;GAAA,GAAA,CAAA;GACE,mBAEQ,gBAAY;sBAAA,OADpB,aAAA;IAAA,mBAIE,gBAIQ;IAQV,OAAA,gBACE,UAAA,GAAA,mBAAA,OAAA,aAAA,CAAA,mBAAA,MAAA,aAAA,gBAAA,OAAA,aAAA,IAAA,GAAA,CAAA,GAAA,OAAA,aAAA,eAAA,UAAA,GAAA,mBAAA,KAAA,aAAA,gBAAA,OAAA,aAAA,WAAA,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,CAAA,KAAA,mBAAA,QAAA,IAAA;IAAA,mBASS,iBAAA"}