-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hover-card): new component (#334)
* feat(hovercard): new component * fix: updated hovercard * fix: fixed hovercard components * fix: update code * chore: refactor * chore: fix lint * fix: code * fix: lint issues * chore: story add * chore: fix ref * chore: add new stories * fix: typecheck * chore: added stories for hovercard * chore: refactor * fix: lock * chore: fix * chore: update read me --------- Co-authored-by: productdevbook <hi@productdevbook.com>
- Loading branch information
1 parent
d2599bd
commit e02c7e8
Showing
33 changed files
with
1,755 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Hover Card | ||
For sighted users to preview content available behind a link. | ||
|
||
![@oku-ui/toast](./../../../.github/assets/og/oku-hover-card.jpg) | ||
|
||
|
||
<span><a href="https://www.npmjs.com/package/@oku-ui/hover-card "><img src="https://img.shields.io/npm/v/@oku-ui/hover-card?style=flat&colorA=18181B&colorB=28CF8D" alt="Version"></a> </span> | <span> <a href="https://www.npmjs.com/package/@oku-ui/hover-card"> <img src="https://img.shields.io/npm/dm/@oku-ui/hover-card?style=flat&colorA=18181B&colorB=28CF8D" alt="Downloads"> </a> </span> | <span> <a href="https://oku-ui.com/primitives/components/hover-card"><img src="https://img.shields.io/badge/Open%20Documentation-18181B" alt="Website"></a> </span> | ||
|
||
## Installation | ||
|
||
```sh | ||
$ pnpm add @oku-ui/hover-card | ||
``` | ||
|
||
[Documentation](https://oku-ui.com/primitives/components/hover-card) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { defineBuildConfig } from 'unbuild' | ||
|
||
const isClean = (process.env.CLEAN || 'false') === 'true' | ||
export default defineBuildConfig({ | ||
declaration: true, | ||
clean: isClean, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"name": "@oku-ui/hover-card", | ||
"type": "module", | ||
"version": "0.2.3", | ||
"license": "MIT", | ||
"source": "src/index.ts", | ||
"funding": "https://github.com/sponsors/productdevbook", | ||
"homepage": "https://oku-ui.com/primitives", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/oku-ui/primitives.git", | ||
"directory": "packages/components/hover-card" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/oku-ui/primitives/issues" | ||
}, | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs" | ||
} | ||
}, | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"scripts": { | ||
"build": "unbuild", | ||
"dev": "unbuild --stub", | ||
"clean": "rimraf ./dist && rimraf ./node_modules" | ||
}, | ||
"peerDependencies": { | ||
"vue": "^3.3.0" | ||
}, | ||
"dependencies": { | ||
"@floating-ui/vue": "^1.0.2", | ||
"@oku-ui/dismissable-layer": "0.4.0-alpha.3", | ||
"@oku-ui/popper": "latest", | ||
"@oku-ui/portal": "latest", | ||
"@oku-ui/presence": "0.4.0-alpha.3", | ||
"@oku-ui/primitive": "latest", | ||
"@oku-ui/provide": "latest", | ||
"@oku-ui/slot": "0.4.0-alpha.3", | ||
"@oku-ui/use-composable": "latest", | ||
"@oku-ui/utils": "latest", | ||
"@oku-ui/visually-hidden": "0.4.0-alpha.3" | ||
}, | ||
"devDependencies": { | ||
"tsconfig": "workspace:^" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import type { PropType, Ref } from 'vue' | ||
import { computed, defineComponent, h, onBeforeUnmount, ref, toRefs, useModel } from 'vue' | ||
import { primitiveProps } from '@oku-ui/primitive' | ||
import { useControllable } from '@oku-ui/use-composable' | ||
import { createProvideScope } from '@oku-ui/provide' | ||
import { OkuPopper, createPopperScope } from '@oku-ui/popper' | ||
import { scopeHoverCardProps } from './utils' | ||
|
||
export const HOVERCARD_NAME = 'OkuHoverCard' | ||
|
||
const [createHoverCardProvider, createHoverCardScope] = createProvideScope(HOVERCARD_NAME, [ | ||
createPopperScope, | ||
]) | ||
|
||
export const usePopperScope = createPopperScope() | ||
|
||
type HoverCardProvideValue = { | ||
open: Ref<boolean> | ||
onOpenChange(open: boolean): void | ||
onOpen(): void | ||
onClose(): void | ||
onDismiss(): void | ||
hasSelectionRef: Ref<boolean> | ||
isPointerDownOnContentRef: Ref<boolean> | ||
} | ||
|
||
export const [hoverCardProvide, useHoverCardInject] | ||
= createHoverCardProvider<HoverCardProvideValue>(HOVERCARD_NAME) | ||
|
||
export interface HoverCardProps { | ||
open?: boolean | ||
defaultOpen?: boolean | ||
openDelay?: number | ||
closeDelay?: number | ||
} | ||
|
||
export type HoverCardEmits = { | ||
'update:modelValue': [open: boolean] | ||
'openChange': [open: boolean] | ||
} | ||
|
||
export const hoverCardProps = { | ||
props: { | ||
modelValue: { | ||
type: [Boolean] as PropType<boolean | undefined>, | ||
default: undefined, | ||
}, | ||
open: { | ||
type: Boolean as PropType<boolean | undefined>, | ||
default: undefined, | ||
}, | ||
defaultOpen: { | ||
type: Boolean as PropType<boolean>, | ||
default: undefined, | ||
}, | ||
openDelay: { | ||
type: Number as PropType<number | undefined>, | ||
default: 700, | ||
}, | ||
closeDelay: { | ||
type: Number as PropType<number | undefined>, | ||
default: 300, | ||
}, | ||
...primitiveProps, | ||
}, | ||
emits: { | ||
// eslint-disable-next-line unused-imports/no-unused-vars | ||
'update:modelValue': (open: boolean) => true, | ||
// eslint-disable-next-line unused-imports/no-unused-vars | ||
'openChange': (open: boolean) => true, | ||
}, | ||
} | ||
|
||
const hoverCard = defineComponent({ | ||
name: HOVERCARD_NAME, | ||
inheritAttrs: false, | ||
props: { | ||
...hoverCardProps.props, | ||
...scopeHoverCardProps, | ||
}, | ||
setup(props, { slots, emit }) { | ||
const { | ||
scopeOkuHoverCard, | ||
open: openProp, | ||
defaultOpen, | ||
openDelay: openDelayProp, | ||
closeDelay: closeDelayProp, | ||
} = toRefs(props) | ||
|
||
const popperScope = usePopperScope(scopeOkuHoverCard.value) | ||
const openTimerRef = ref(0) | ||
const closeTimerRef = ref(0) | ||
const hasSelectionRef = ref(false) | ||
const isPointerDownOnContentRef = ref(false) | ||
|
||
const modelValue = useModel(props, 'modelValue') | ||
const proxyChecked = computed({ | ||
get: () => modelValue.value !== undefined ? modelValue.value : openProp.value !== undefined ? openProp.value : undefined, | ||
set: () => { | ||
}, | ||
}) | ||
|
||
const { state, updateValue } = useControllable({ | ||
prop: computed(() => proxyChecked.value), | ||
defaultProp: computed(() => defaultOpen.value), | ||
onChange: (value) => { | ||
emit('openChange', value) | ||
modelValue.value = value | ||
}, | ||
initialValue: false, | ||
}) | ||
|
||
const handleOpen = () => { | ||
clearTimeout(closeTimerRef.value) | ||
openTimerRef.value = window.setTimeout(() => { | ||
updateValue(true) | ||
}, openDelayProp.value) | ||
} | ||
|
||
const handleClose = () => { | ||
clearTimeout(openTimerRef.value) | ||
if (!hasSelectionRef.value && !isPointerDownOnContentRef.value) { | ||
closeTimerRef.value = window.setTimeout(() => { | ||
updateValue(false) | ||
}, closeDelayProp.value) | ||
} | ||
} | ||
|
||
const handleDismiss = () => { | ||
updateValue(false) | ||
} | ||
|
||
onBeforeUnmount(() => { | ||
clearTimeout(openTimerRef.value) | ||
clearTimeout(closeTimerRef.value) | ||
}) | ||
|
||
hoverCardProvide({ | ||
scope: scopeOkuHoverCard.value, | ||
open: computed(() => state.value || false), | ||
onOpenChange: open => updateValue(open), | ||
onOpen: () => handleOpen(), | ||
onClose: () => handleClose(), | ||
onDismiss: () => handleDismiss(), | ||
hasSelectionRef, | ||
isPointerDownOnContentRef, | ||
}) | ||
|
||
return () => h(OkuPopper, { | ||
...popperScope, | ||
}, slots) | ||
}, | ||
}) | ||
|
||
export const OkuHoverCard = hoverCard | ||
|
||
export { | ||
createHoverCardScope, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { defineComponent, h, mergeProps, reactive } from 'vue' | ||
import { reactiveOmit, useForwardRef } from '@oku-ui/use-composable' | ||
import { OkuPopperArrow, type PopperArrowElement, type PopperArrowNaviteElement, type PopperArrowProps, popperArrowProps } from '@oku-ui/popper' | ||
import { usePopperScope } from './hoverCard' | ||
import { scopeHoverCardProps } from './utils' | ||
|
||
const ARROW_NAME = 'OkuHoverCardArrow' | ||
|
||
export type HoverCardArrowNaviteElement = PopperArrowNaviteElement | ||
export type HoverCardArrowElement = PopperArrowElement | ||
export interface HoverCardArrowProps extends PopperArrowProps { } | ||
|
||
export const hoverCardArrowProps = { | ||
props: { | ||
...popperArrowProps.props, | ||
}, | ||
emits: { | ||
...popperArrowProps.emits, | ||
}, | ||
} | ||
|
||
const hoverCardArrow = defineComponent({ | ||
name: ARROW_NAME, | ||
components: { | ||
OkuPopperArrow, | ||
}, | ||
inheritAttrs: false, | ||
props: { | ||
...hoverCardArrowProps.props, | ||
...scopeHoverCardProps, | ||
}, | ||
emits: hoverCardArrowProps.emits, | ||
setup(props, { attrs, slots }) { | ||
const { scopeOkuHoverCard, ...arrowProps } = props | ||
|
||
const _reactive = reactive(arrowProps) | ||
const reactiveArrowProps = reactiveOmit(_reactive, (key, _value) => key === undefined) | ||
|
||
const forwardedRef = useForwardRef() | ||
const popperScope = usePopperScope(scopeOkuHoverCard) | ||
|
||
// if the arrow is inside the `VisuallyHidden`, we don't want to render it all to | ||
// prevent issues in positioning the arrow due to the duplicate | ||
return () => h(OkuPopperArrow, { | ||
...popperScope, | ||
...mergeProps(attrs, reactiveArrowProps), | ||
ref: forwardedRef, | ||
}, slots) | ||
}, | ||
}) | ||
|
||
export const OkuHoverCardArrow = hoverCardArrow as typeof hoverCardArrow & | ||
(new () => { | ||
$props: HoverCardArrowNaviteElement | ||
}) |
Oops, something went wrong.