Skip to content

Commit c402fd9

Browse files
productdevbookdammy001autofix-ci[bot]
authored
feat: popper component (#190)
* feat: popper component * add root popper * refactor: storybook stories array used globbysync * fix: popper * fix: pnpm lock * [autofix.ci] apply automated fixes * add: playground * fix: popper content value * feat: add onAnchorChange * feat: add props child * fix: position --------- Co-authored-by: Damilare Anjorin <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent a04fba8 commit c402fd9

27 files changed

+1090
-6
lines changed

.storybook/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { StorybookConfig } from "@storybook/vue3-vite";
2-
2+
import {globbySync} from "globby"
33
const config: StorybookConfig = {
4-
stories: ["../stories/**/*.mdx", "../packages/components/**/*.stories.@(js|jsx|ts|tsx)"],
4+
stories: globbySync(['../stories/*.mdx', `../**/*.stories.@(js|jsx|ts|tsx)`, "!../**/node_modules/**/*"], { cwd: "./.storybook" }),
55
addons: [
66
"@storybook/addon-links",
77
"@storybook/addon-essentials",

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build": "turbo run build --filter='./packages/**'",
1313
"build:components": "turbo run build --filter='./packages/components/**'",
1414
"build:core": "turbo run build --filter='./packages/core/**'",
15-
"dev": "pnpm storybook dev -p 6006",
15+
"dev": "pnpm storybook dev -p 6006 --no-open",
1616
"dev:all": "turbo run dev --filter='./packages/**' --concurrency $(($(ls -1 packages/components packages/core | wc -l)+3))",
1717
"dev:core": "turbo run dev --filter='./packages/core/**'",
1818
"dev:components": "turbo run dev --filter='./packages/components/**'",
@@ -39,6 +39,7 @@
3939
"@oku-ui/avatar": "workspace:^",
4040
"@oku-ui/checkbox": "workspace:^",
4141
"@oku-ui/label": "workspace:^",
42+
"@oku-ui/popper": "workspace:^",
4243
"@oku-ui/progress": "workspace:^",
4344
"@oku-ui/separator": "workspace:^",
4445
"@oku-ui/toggle": "workspace:^",

packages/components/popper/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# `@oku-ui/toggle`
2+
3+
## Installation
4+
5+
```sh
6+
$ pnpm add @oku-ui/toggle
7+
```
8+
9+
## Usage
10+
...
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineBuildConfig } from 'unbuild'
2+
3+
export default defineBuildConfig({
4+
entries: [
5+
{
6+
builder: 'mkdist',
7+
input: './src/',
8+
pattern: ['**/!(*.test|*.stories).ts'],
9+
},
10+
],
11+
declaration: true,
12+
})
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "@oku-ui/popper",
3+
"type": "module",
4+
"version": "0.1.0",
5+
"license": "MIT",
6+
"source": "src/index.ts",
7+
"funding": "https://github.com/sponsors/productdevbook",
8+
"homepage": "https://oku-ui.com/primitives",
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/oku-ui/primitives.git",
12+
"directory": "packages/components/popper"
13+
},
14+
"bugs": {
15+
"url": "https://github.com/oku-ui/primitives/issues"
16+
},
17+
"exports": {
18+
".": {
19+
"types": "./dist/index.d.ts",
20+
"import": "./dist/index.mjs"
21+
}
22+
},
23+
"module": "./dist/index.mjs",
24+
"types": "./dist/index.d.ts",
25+
"files": [
26+
"dist"
27+
],
28+
"scripts": {
29+
"build": "tsup",
30+
"dev": "tsup --watch"
31+
},
32+
"peerDependencies": {
33+
"vue": "^3.3.1"
34+
},
35+
"dependencies": {
36+
"@floating-ui/vue": "^1.0.1",
37+
"@oku-ui/arrow": "workspace:^",
38+
"@oku-ui/primitive": "workspace:^",
39+
"@oku-ui/provide": "workspace:^",
40+
"@oku-ui/use-composable": "workspace:^",
41+
"@oku-ui/utils": "workspace:^"
42+
},
43+
"devDependencies": {
44+
"tsconfig": "workspace:^"
45+
}
46+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export {
2+
OkuPopper,
3+
} from './popper'
4+
5+
export type {
6+
PopperRef,
7+
PopperProps,
8+
} from './popper'
9+
10+
export {
11+
OkuPopperAnchor,
12+
} from './popperAnchor'
13+
14+
export type {
15+
PopperAnchorProps,
16+
} from './popperAnchor'
17+
18+
export {
19+
OkuPopperContent,
20+
} from './popperContent'
21+
22+
export type {
23+
PopperContentProps,
24+
} from './popperContent'
25+
26+
export {
27+
OkuPopperArrow,
28+
} from './popperArrow'
29+
30+
export type {
31+
PopperArrowProps,
32+
} from './popperArrow'
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { mount } from '@vue/test-utils'
3+
import { OkuPopper } from './popper'
4+
5+
describe('OkuPopper', () => {
6+
it('renders correctly', () => {
7+
const wrapper = mount(OkuPopper)
8+
expect(wrapper.html()).toBe('')
9+
})
10+
11+
// it('Active state', () => {
12+
// const wrapper = shallowMount(OkuToggle, {
13+
// propsData: {
14+
// defaultPressed: true,
15+
// },
16+
// })
17+
// expect(wrapper.attributes('aria-pressed')).toBe('true')
18+
// })
19+
20+
// it('Inactive state', () => {
21+
// const wrapper = shallowMount(OkuToggle, {
22+
// propsData: {
23+
// defaultPressed: false,
24+
// },
25+
// })
26+
// expect(wrapper.attributes('aria-pressed')).toBe('false')
27+
// })
28+
29+
// it('Toggle state', async () => {
30+
// const wrapper = mount(OkuToggle, {
31+
// })
32+
// await wrapper.trigger('click')
33+
// expect(wrapper.attributes('aria-pressed')).toBe('true')
34+
// await wrapper.trigger('click')
35+
// expect(wrapper.attributes('aria-pressed')).toBe('false')
36+
// })
37+
})
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { PropType, Ref } from 'vue'
2+
import { defineComponent, ref, toRefs } from 'vue'
3+
4+
import type { RefElement } from '@oku-ui/primitive'
5+
import type { Measurable } from '@oku-ui/utils'
6+
import type { Scope } from '@oku-ui/provide'
7+
import { createProvideScope } from '@oku-ui/provide'
8+
9+
/* -------------------------------------------------------------------------------------------------
10+
* Popper
11+
* ----------------------------------------------------------------------------------------------- */
12+
13+
const POPPER_NAME = 'Popper'
14+
15+
export const [createPopperProvider, _createPopperScope] = createProvideScope(POPPER_NAME)
16+
17+
export type PopperInjectValue = {
18+
anchor: Ref<Measurable | null>
19+
onAnchorChange(anchor: Measurable | null): void
20+
}
21+
22+
export const [PopperProvider, usePopperInject]
23+
= createPopperProvider<PopperInjectValue>(POPPER_NAME)
24+
25+
interface PopperProps {
26+
scopeCheckbox?: Scope
27+
}
28+
29+
const Popper = defineComponent({
30+
name: POPPER_NAME,
31+
inheritAttrs: false,
32+
props: {
33+
scopeCheckbox: {
34+
type: Object as unknown as PropType<Scope>,
35+
required: false,
36+
default: undefined,
37+
},
38+
},
39+
setup(props, { attrs, expose, slots }) {
40+
const { scopeCheckbox } = toRefs(props)
41+
const anchor = ref<Measurable | null>(null)
42+
43+
PopperProvider({
44+
scope: scopeCheckbox.value as Scope,
45+
anchor,
46+
onAnchorChange(_anchor: Measurable | null) {
47+
anchor.value = _anchor
48+
},
49+
})
50+
51+
const originalReturn = () => slots.default?.()
52+
53+
return originalReturn
54+
},
55+
})
56+
57+
type _PopperProps = PopperProps
58+
59+
type PopperRef = RefElement<typeof Popper>
60+
61+
const OkuPopper = Popper as typeof Popper & (new () => { $props: _PopperProps })
62+
63+
export {
64+
OkuPopper,
65+
}
66+
67+
export type {
68+
PopperProps,
69+
PopperRef,
70+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import type { PropType, Ref } from 'vue'
2+
import { defineComponent, h, toRefs, watch } from 'vue'
3+
4+
import type { ElementType, MergeProps, PrimitiveProps } from '@oku-ui/primitive'
5+
import type { Measurable } from '@oku-ui/utils'
6+
import type { Scope } from '@oku-ui/provide'
7+
import { useRef } from '@oku-ui/use-composable'
8+
import { Primitive } from '@oku-ui/primitive'
9+
import { usePopperInject } from './popper'
10+
11+
/* -------------------------------------------------------------------------------------------------
12+
* PopperAnchor
13+
* ----------------------------------------------------------------------------------------------- */
14+
15+
const ANCHOR_NAME = 'PopperAnchor'
16+
17+
type PopperAnchorElement = ElementType<'div'>
18+
interface PopperAnchorProps extends PrimitiveProps {
19+
virtualRef?: Ref<Measurable | null>
20+
scopeCheckbox?: Scope
21+
}
22+
23+
const PopperAnchor = defineComponent({
24+
name: ANCHOR_NAME,
25+
inheritAttrs: false,
26+
props: {
27+
virtualRef: {
28+
type: Object as unknown as PropType<Ref<Measurable | null>>,
29+
required: false,
30+
default: undefined,
31+
},
32+
scopeCheckbox: {
33+
type: Object as unknown as PropType<Scope>,
34+
required: false,
35+
default: undefined,
36+
},
37+
asChild: {
38+
type: Boolean,
39+
default: false,
40+
},
41+
},
42+
setup(props, { attrs, expose, slots }) {
43+
const { virtualRef, scopeCheckbox } = toRefs(props)
44+
const { ...attrsAnchor } = attrs as PopperAnchorElement
45+
const inject = usePopperInject(ANCHOR_NAME, scopeCheckbox.value)
46+
const { $el, newRef } = useRef<Measurable>()
47+
48+
watch($el, () => {
49+
inject.value.anchor.value = virtualRef.value?.value || $el.value as Measurable
50+
})
51+
52+
const originalReturn = () => virtualRef.value
53+
? null
54+
: h(Primitive.div, {
55+
...attrsAnchor,
56+
asChild: props.asChild,
57+
ref: newRef,
58+
},
59+
{
60+
default: () => slots.default && slots.default?.(),
61+
},
62+
)
63+
64+
return originalReturn
65+
},
66+
})
67+
68+
type _PopperAnchor = MergeProps<PopperAnchorProps, PopperAnchorElement>
69+
70+
const OkuPopperAnchor = PopperAnchor as typeof PopperAnchor & (new () => { $props: _PopperAnchor })
71+
72+
export {
73+
OkuPopperAnchor,
74+
}
75+
76+
export type {
77+
PopperAnchorProps,
78+
PopperAnchorElement,
79+
}

0 commit comments

Comments
 (0)