Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions packages/core/src/Combobox/story/ComboboxShadowRoot.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<script setup lang="ts">
import type { Component } from 'vue'
import { createApp, useTemplateRef, watch } from 'vue'

import _Dialog from './_Dialog.vue'

const options = [
{ name: 'Fruit', children: [
{ name: 'Apple' },
{ name: 'Banana' },
{ name: 'Orange' },
{ name: 'Honeydew' },
{ name: 'Grapes' },
{ name: 'Watermelon' },
{ name: 'Cantaloupe' },
{ name: 'Pear' },
] },
{ name: 'Vegetable', children: [
{ name: 'Cabbage' },
{ name: 'Broccoli' },
{ name: 'Carrots' },
{ name: 'Lettuce' },
{ name: 'Spinach' },
{ name: 'Bok Choy' },
{ name: 'Cauliflower' },
{ name: 'Potatoes' },
] },
]

function mountShadowRoot(container: HTMLDivElement, component: Component) {
const elementWithShadow = container as Element & { shadowRoot: ShadowRoot | null }
const shadowRoot
= elementWithShadow.shadowRoot || elementWithShadow.attachShadow({ mode: 'open' })

document.querySelectorAll('style, link[rel="stylesheet"]').forEach((node) => {
shadowRoot.appendChild(node.cloneNode(true))
})

const shadowMountPoint = document.createElement('div')
shadowRoot.appendChild(shadowMountPoint)

const shadowPortalTarget = document.createElement('div')
shadowPortalTarget.id = `portal-shadow-root`
shadowRoot.appendChild(shadowPortalTarget)

createApp(component, {
dialogPortalTarget: shadowPortalTarget,
}).mount(shadowMountPoint)
}

function resetShadowRoot(container: HTMLDivElement) {
const elementWithShadow = container as Element & { shadowRoot: ShadowRoot | null }
if (elementWithShadow.shadowRoot) {
elementWithShadow.shadowRoot.innerHTML = ''
}
}

const container = useTemplateRef('container')

watch(
container,
(newVal) => {
if (newVal) {
resetShadowRoot(newVal)
mountShadowRoot(newVal, _Dialog)
}
},
{ immediate: true },
)
</script>

<template>
<Story
title="Combobox/ShadowRoot"
:layout="{ type: 'single', iframe: false }"
>
<Variant title="default">
<div
id="shadow-root-container"
ref="container"
class="h-96"
/>
</Variant>
</Story>
</template>
73 changes: 73 additions & 0 deletions packages/core/src/Combobox/story/_Dialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
DialogClose,
DialogContent,
DialogOverlay,
DialogPortal,
DialogRoot,
DialogTitle,
DialogTrigger,
} from '../../Dialog'
import ComboboxManualFilter from './_ComboboxManualFilter.vue'

defineProps<{ dialogPortalTarget: HTMLDivElement }>()
const dialogOpen = ref(false)
</script>

<template>
<DialogRoot v-model:open="dialogOpen">
<DialogTrigger
class="text-violet11 shadow-blackA7 hover:bg-mauve3 inline-flex h-[35px] items-center justify-center rounded-[4px] bg-white px-[15px] font-medium leading-none shadow-[0_2px_10px] focus:shadow-[0_0_0_2px] focus:shadow-black focus:outline-none"
>
Edit profile
</DialogTrigger>
<DialogPortal :to="dialogPortalTarget">
<Transition name="fade">
<DialogOverlay
class="bg-blackA9 fixed inset-0"
/>
</Transition>
<Transition name="fade">
<DialogContent
:is-escape-key-down-default="true"
class="fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[450px] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-white p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none"
@pointer-down-outside.prevent
>
<DialogTitle class="text-mauve12 m-0 text-[17px] font-medium">
Edit profile
</DialogTitle>
<ComboboxManualFilter />
<div class="mt-[25px] flex justify-end">
<DialogClose as-child>
<button
class="bg-green4 text-green11 hover:bg-green5 focus:shadow-green7 inline-flex h-[35px] items-center justify-center rounded-[4px] px-[15px] font-medium leading-none focus:shadow-[0_0_0_2px] focus:outline-none"
>
Save changes
</button>
</DialogClose>
</div>
<DialogClose
class="text-violet11 hover:bg-violet4 focus:shadow-violet7 absolute top-[10px] right-[10px] inline-flex h-[25px] w-[25px] appearance-none items-center justify-center rounded-full focus:shadow-[0_0_0_2px] focus:outline-none"
aria-label="Close"
>
<Icon icon="lucide:x" />
</DialogClose>
</DialogContent>
</Transition>
</DialogPortal>
</DialogRoot>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
Loading