Skip to content

Commit

Permalink
Transition component (#326)
Browse files Browse the repository at this point in the history
* add redent function when verifying snapshots

This allows us not to care about the correct amount of spaces and always
produces a clean output.

* make the container the parent of the wrapper element

* drop the visible prop on the Portal component

* drop visible prop on Portal component

+ Also cleanup a little bit

* expose the RenderStrategy

* implement Transition component in Vue

* expose Transition component

* add Transitions to the Dialog example
  • Loading branch information
RobinMalfait authored Apr 12, 2021
1 parent 6fa6c45 commit 0a39cf6
Show file tree
Hide file tree
Showing 21 changed files with 3,057 additions and 409 deletions.
386 changes: 193 additions & 193 deletions packages/@headlessui-react/src/components/transitions/transition.test.tsx

Large diffs are not rendered by default.

41 changes: 31 additions & 10 deletions packages/@headlessui-react/src/test-utils/execute-timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ import { render } from '@testing-library/react'
import { disposables } from '../utils/disposables'
import { reportChanges } from './report-dom-node-changes'

function redentSnapshot(input: string) {
let minSpaces = Infinity
let lines = input.split('\n')
for (let line of lines) {
if (line.trim() === '---') continue
let spacesInLine = (line.match(/^[+-](\s+)/g) || []).pop()!.length - 1
minSpaces = Math.min(minSpaces, spacesInLine)
}

let replacer = new RegExp(`^([+-])\\s{${minSpaces}}(.*)`, 'g')

return input
.split('\n')
.map(line =>
line.trim() === '---' ? line : line.replace(replacer, (_, sign, rest) => `${sign} ${rest}`)
)
.join('\n')
}

export async function executeTimeline(
element: JSX.Element,
steps: ((tools: ReturnType<typeof render>) => (null | number)[])[]
Expand Down Expand Up @@ -95,16 +114,18 @@ export async function executeTimeline(
? 'yes'
: `no, it took ${call.relativeToPreviousSnapshot}ms`
})`
}\n${snapshotDiff(uniqueSnapshots[i - 1].content, call.content, {
aAnnotation: '__REMOVE_ME__',
bAnnotation: '__REMOVE_ME__',
contextLines: 0,
})
// Just to do some cleanup
.replace(/\n\n@@([^@@]*)@@/g, '') // Top level @@ signs
.replace(/@@([^@@]*)@@/g, '---') // In between @@ signs
.replace(/[-+] __REMOVE_ME__\n/g, '')
.replace(/Snapshot Diff:\n/g, '')
}\n${redentSnapshot(
snapshotDiff(uniqueSnapshots[i - 1].content, call.content, {
aAnnotation: '__REMOVE_ME__',
bAnnotation: '__REMOVE_ME__',
contextLines: 0,
})
// Just to do some cleanup
.replace(/\n\n@@([^@@]*)@@/g, '') // Top level @@ signs
.replace(/@@([^@@]*)@@/g, '---') // In between @@ signs
.replace(/[-+] __REMOVE_ME__\n/g, '')
.replace(/Snapshot Diff:\n/g, '')
)
.split('\n')
.map(line => ` ${line}`)
.join('\n')}`
Expand Down
1 change: 1 addition & 0 deletions packages/@headlessui-vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ _This project is still in early development. New components will be added regula
- [Dialog](./src/components/dialog/README.md)
- [Popover](./src/components/popover/README.md)
- [Radio Group](./src/components/radio-group/README.md)
- [Transition](./src/components/transitions/README.md)

### Roadmap

Expand Down
264 changes: 149 additions & 115 deletions packages/@headlessui-vue/examples/src/components/dialog/dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,132 +7,162 @@
Toggle!
</button>

<Dialog :open="isOpen" :onClose="setIsOpen">
<div class="fixed z-10 inset-0 overflow-y-auto">
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<DialogOverlay class="fixed inset-0 transition-opacity">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</DialogOverlay>

<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
&#8203;
</span>
<TransitionRoot :show="isOpen" as="template">
<Dialog :open="isOpen" @close="setIsOpen" static>
<div class="fixed z-10 inset-0 overflow-y-auto">
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"
>
<!-- Heroicon name: exclamation -->
<svg
class="h-6 w-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<DialogTitle as="h3" class="text-lg leading-6 font-medium text-gray-900">
Deactivate account
</DialogTitle>
<div class="mt-2">
<p class="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will be
permanently removed. This action cannot be undone.
</p>
<div class="relative inline-block text-left mt-10">
<Menu v-slot="{ open }">
<span class="rounded-md shadow-sm">
<MenuButton
ref="trigger"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Choose a reason</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<TransitionChild
as="template"
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<DialogOverlay class="fixed inset-0 transition-opacity">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</DialogOverlay>
</TransitionChild>

<TransitionChild
enter="ease-out transform duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in transform duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
&#8203;
</span>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"
>
<!-- Heroicon name: exclamation -->
<svg
class="h-6 w-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<DialogTitle as="h3" class="text-lg leading-6 font-medium text-gray-900">
Deactivate account
</DialogTitle>
<div class="mt-2">
<p class="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will be
permanently removed. This action cannot be undone.
</p>
<div class="relative inline-block text-left mt-10">
<Menu v-slot="{ open }">
<span class="rounded-md shadow-sm">
<MenuButton
ref="trigger"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Choose a reason</span>
<svg
class="w-5 h-5 ml-2 -mr-1"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>

<Portal v-if="open">
<MenuItems
static
ref="container"
class="z-20 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">
[email protected]
</p>
</div>
<Portal v-if="open">
<MenuItems
static
ref="container"
class="z-20 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">
[email protected]
</p>
</div>

<div class="py-1">
<MenuItem as="a" href="#account-settings" :className="resolveClass">
Account settings
</MenuItem>
<MenuItem as="a" href="#support" :className="resolveClass">
Support
</MenuItem>
<MenuItem as="a" disabled href="#new-feature" :className="resolveClass">
New feature (soon)
</MenuItem>
<MenuItem as="a" href="#license" :className="resolveClass">
License
</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" href="#account-settings" :className="resolveClass">
Account settings
</MenuItem>
<MenuItem as="a" href="#support" :className="resolveClass">
Support
</MenuItem>
<MenuItem
as="a"
disabled
href="#new-feature"
:className="resolveClass"
>
New feature (soon)
</MenuItem>
<MenuItem as="a" href="#license" :className="resolveClass">
License
</MenuItem>
</div>

<div class="py-1">
<MenuItem as="a" href="#sign-out" :className="resolveClass">
Sign out
</MenuItem>
</div>
</MenuItems>
</Portal>
</Menu>
<div class="py-1">
<MenuItem as="a" href="#sign-out" :className="resolveClass">
Sign out
</MenuItem>
</div>
</MenuItems>
</Portal>
</Menu>
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
@click="setIsOpen(false)"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:shadow-outline-red sm:ml-3 sm:w-auto sm:text-sm"
>
Deactivate
</button>
<button
type="button"
@click="setIsOpen(false)"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:shadow-outline-indigo sm:mt-0 sm:w-auto sm:text-sm"
>
Cancel
</button>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
@click="setIsOpen(false)"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:shadow-outline-red sm:ml-3 sm:w-auto sm:text-sm"
>
Deactivate
</button>
<button
type="button"
@click="setIsOpen(false)"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:shadow-outline-indigo sm:mt-0 sm:w-auto sm:text-sm"
>
Cancel
</button>
</div>
</TransitionChild>
</div>
</div>
</div>
</Dialog>
</Dialog>
</TransitionRoot>
</template>

<script>
Expand All @@ -146,6 +176,8 @@ import {
MenuItems,
MenuItem,
Portal,
Transition,
TransitionChild,
} from '@headlessui/vue'
import { usePopper } from '../../playground-utils/hooks/use-popper'
Expand All @@ -171,6 +203,8 @@ export default {
MenuItems,
MenuItem,
Portal,
TransitionRoot: Transition,
TransitionChild,
},
setup() {
let isOpen = ref(false)
Expand Down
Loading

0 comments on commit 0a39cf6

Please sign in to comment.