From ae2b6859b89783f3e8b9f8f8df56910485177ac6 Mon Sep 17 00:00:00 2001 From: Ejiro Asiuwhu Date: Sun, 9 Jul 2023 17:30:36 +0100 Subject: [PATCH 01/13] feat(wip): add base for tab component --- packages/components/tabs/README.md | 10 ++ packages/components/tabs/build.config.ts | 12 ++ packages/components/tabs/package.json | 44 +++++++ packages/components/tabs/src/index.ts | 7 ++ packages/components/tabs/src/tab-content.ts | 30 +++++ packages/components/tabs/src/tab-list.ts | 69 +++++++++++ packages/components/tabs/src/tab-trigger.ts | 27 +++++ packages/components/tabs/src/tabs.ts | 121 ++++++++++++++++++++ packages/components/tabs/tsconfig.json | 10 ++ packages/components/tabs/tsup.config.ts | 22 ++++ 10 files changed, 352 insertions(+) create mode 100644 packages/components/tabs/README.md create mode 100644 packages/components/tabs/build.config.ts create mode 100644 packages/components/tabs/package.json create mode 100644 packages/components/tabs/src/index.ts create mode 100644 packages/components/tabs/src/tab-content.ts create mode 100644 packages/components/tabs/src/tab-list.ts create mode 100644 packages/components/tabs/src/tab-trigger.ts create mode 100644 packages/components/tabs/src/tabs.ts create mode 100644 packages/components/tabs/tsconfig.json create mode 100644 packages/components/tabs/tsup.config.ts diff --git a/packages/components/tabs/README.md b/packages/components/tabs/README.md new file mode 100644 index 000000000..31237339f --- /dev/null +++ b/packages/components/tabs/README.md @@ -0,0 +1,10 @@ +# `@oku-ui/tabs` + +## Installation + +```sh +$ pnpm add @oku-ui/tabs +``` + +## Usage +... \ No newline at end of file diff --git a/packages/components/tabs/build.config.ts b/packages/components/tabs/build.config.ts new file mode 100644 index 000000000..b972b9a78 --- /dev/null +++ b/packages/components/tabs/build.config.ts @@ -0,0 +1,12 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + { + builder: 'mkdist', + input: './src/', + pattern: ['**/!(*.test|*.stories).ts'], + }, + ], + declaration: true, +}) diff --git a/packages/components/tabs/package.json b/packages/components/tabs/package.json new file mode 100644 index 000000000..ed6a62940 --- /dev/null +++ b/packages/components/tabs/package.json @@ -0,0 +1,44 @@ +{ + "name": "@oku-ui/tabs", + "type": "module", + "version": "0.1.0", + "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/tabs" + }, + "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" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch" + }, + "peerDependencies": { + "vue": "^3.3.4" + }, + "dependencies": { + "@oku-ui/primitive": "workspace:^", + "@oku-ui/provide": "workspace:^", + "@oku-ui/use-composable": "workspace:^", + "@oku-ui/utils": "workspace:^" + }, + "devDependencies": { + "tsconfig": "workspace:^" + } +} diff --git a/packages/components/tabs/src/index.ts b/packages/components/tabs/src/index.ts new file mode 100644 index 000000000..7648ba21f --- /dev/null +++ b/packages/components/tabs/src/index.ts @@ -0,0 +1,7 @@ +export { OkuTabs } from './tabs' +export { OkuTabList } from './tab-list' +export { OkuTabTrigger } from './tab-trigger' +export { OkuTabContent } from './tab-content' + +export type { TabsProps } from './tabs' +export { type TabListProps } from './tab-list' diff --git a/packages/components/tabs/src/tab-content.ts b/packages/components/tabs/src/tab-content.ts new file mode 100644 index 000000000..b2004a4df --- /dev/null +++ b/packages/components/tabs/src/tab-content.ts @@ -0,0 +1,30 @@ +import { type PropType, defineComponent, h } from 'vue' + +const TAB_CONTENT_NAME = 'TabContent' as const + +const TabContent = defineComponent({ + name: TAB_CONTENT_NAME, + inheritAttrs: false, + props: { + activeTab: { + type: String as PropType, + required: true, + }, + value: { + type: String as PropType, + required: true, + }, + }, + setup(props, { slots }) { + const slot = slots.default ? slots.default() : [] + return () => { + if (props.activeTab === props.value) + return h('div', { class: 'tab-content' }, slot) + else return null + } + }, +}) + +const OkuTabContent = TabContent as typeof TabContent + +export { OkuTabContent } diff --git a/packages/components/tabs/src/tab-list.ts b/packages/components/tabs/src/tab-list.ts new file mode 100644 index 000000000..59d8b40c4 --- /dev/null +++ b/packages/components/tabs/src/tab-list.ts @@ -0,0 +1,69 @@ +import type { MergeProps, PrimitiveProps } from '@oku-ui/primitive' +import { type PropType, defineComponent, h } from 'vue' + +/* ------------------------------------------------------------------------------------------------- + * TabList + * ----------------------------------------------------------------------------------------------- */ + +const TAB_LIST_NAME = 'TabList' as const + +interface TabListProps extends PrimitiveProps { + /** + * The active tab value. + * @default 'tab1' + * @type string + * @example + * ```vue + * + * + * // ... + * + * + * ``` + * @see link-to-oku-docs/tab + * */ + activeTab: string + /** + * The callback function that is called when the tab value changes. + * @default () => {} + * @type (value: string) => void + * @example + * ```vue + * console.log(value)}> + * console.log(value)}> + // ... + * + * + * ``` + * @see link-to-oku-docs/tab + * */ + onChange: (value: string) => void +} + +const TabList = defineComponent({ + name: TAB_LIST_NAME, + inheritAttrs: false, + props: { + activeTab: { + type: String as PropType, + required: true, + }, + onChange: { + type: Function as PropType<(value: string) => void>, + required: true, + }, + }, + setup(_, { slots }) { + const slot = slots.default ? slots.default() : [] + + return () => h('div', { 'data-attr': 'tab-list' }, slot) + }, +}) + +type _TabListProps = MergeProps + +const OkuTabList = TabList as typeof TabList & (new () => { $props: _TabListProps }) + +export { OkuTabList } + +export type { TabListProps } diff --git a/packages/components/tabs/src/tab-trigger.ts b/packages/components/tabs/src/tab-trigger.ts new file mode 100644 index 000000000..676113f25 --- /dev/null +++ b/packages/components/tabs/src/tab-trigger.ts @@ -0,0 +1,27 @@ +import { type PropType, defineComponent, h } from 'vue' + +const TAB_TRIGGER_NAME = 'TabTrigger' as const + +const TabTrigger = defineComponent({ + name: TAB_TRIGGER_NAME, + inheritAttrs: false, + props: { + value: { + type: String as PropType, + required: true, + }, + }, + setup(props, { slots, emit }) { + const handleClick = () => { + emit('change', props.value) + } + + const slot = slots.default ? slots.default() : [] + + return () => h('button', { onClick: handleClick }, slot) + }, +}) + +const OkuTabTrigger = TabTrigger as typeof TabTrigger + +export { OkuTabTrigger } diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts new file mode 100644 index 000000000..ffd00d6d7 --- /dev/null +++ b/packages/components/tabs/src/tabs.ts @@ -0,0 +1,121 @@ +import type { MergeProps, PrimitiveProps } from '@oku-ui/primitive' +import { type PropType, defineComponent, h, ref } from 'vue' +import { OkuTabContent } from './tab-content' +import { OkuTabList } from './tab-list' + +/* ------------------------------------------------------------------------------------------------- + * Tabs + * ----------------------------------------------------------------------------------------------- */ + +const TAB_NAME = 'TAB' as const + +interface TabsProps extends PrimitiveProps { + /** + * The default value of the tab. + * @default 'tab1' + * @type string + * @example + * ```vue + * + // ... + * + * ``` + * @see link-to-oku-docs/tab + */ + defaultValue?: string + /** + * The callback function that is called when the tab value changes. + * @default () => {} + * @type (value: string) => void + * @example + * ```vue + * console.log(value)}> + // ... + * + * */ + onValueChange?: (value: string) => void + /** + * The orientation of the tabs. + * @default 'horizontal' + * @type 'horizontal' | 'vertical' + * @example + * ```vue + * + // ... + * + * ``` + * @see link-to-oku-docs/tab + * */ + orientation?: 'horizontal' | 'vertical' +} + +const Tabs = defineComponent({ + name: TAB_NAME, + inheritAttrs: false, + props: { + defaultValue: { + type: String as PropType, + default: 'tab1', + }, + onValueChange: { + type: Function as PropType<(value: string) => void>, + default: () => {}, + }, + orientation: { + type: String as PropType<'horizontal' | 'vertical'>, + default: 'horizontal', + }, + }, + setup(props, { slots }) { + const activeTab = ref(props.defaultValue) + + const handleTabChange = (value: string) => { + activeTab.value = value + props.onValueChange?.(value) + } + + return () => { + const tabListSlot = slots.default + ? slots.default({ activeTab: activeTab.value }) + : [] + const tabContentSlot = slots.tabContent + ? slots.tabContent({ activeTab: activeTab.value }) + : [] + + return h('div', {}, [ + h( + // TODO: fix this + // @ts-expect-error + OkuTabList, + { + activeTab: activeTab.value, + onChange: handleTabChange, + }, + tabListSlot, + ), + h( + // TODO: fix this + // @ts-expect-error + OkuTabContent, + { + activeTab: activeTab.value, + }, + tabContentSlot.map(contentVNode => + h(OkuTabContent, { + activeTab: activeTab.value, + value: contentVNode.props?.value, + }), + ), + ), + ]) + } + }, +}) + +type _TabsProps = MergeProps + +const OkuTabs = Tabs as typeof Tabs & (new () => { $props: _TabsProps }) + +export { OkuTabs } + +export type { TabsProps } diff --git a/packages/components/tabs/tsconfig.json b/packages/components/tabs/tsconfig.json new file mode 100644 index 000000000..b8dfa9041 --- /dev/null +++ b/packages/components/tabs/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "tsconfig/node16.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/packages/components/tabs/tsup.config.ts b/packages/components/tabs/tsup.config.ts new file mode 100644 index 000000000..a2f7a0d8b --- /dev/null +++ b/packages/components/tabs/tsup.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'tsup' +import pkg from './package.json' + +const external = [ + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.peerDependencies || {}), +] + +export default defineConfig((options) => { + return [ + { + ...options, + entryPoints: ['src/index.ts'], + external, + dts: true, + clean: true, + target: 'node16', + format: ['esm'], + outExtension: () => ({ js: '.mjs' }), + }, + ] +}) From 95acd89fd29919f3922cb5f693f46d83d7162be0 Mon Sep 17 00:00:00 2001 From: Ejiro Asiuwhu Date: Thu, 20 Jul 2023 03:33:42 +0100 Subject: [PATCH 02/13] feat: add function for tab components --- package.json | 4 + packages/components/tabs/src/index.ts | 4 +- .../components/tabs/src/stories/TabsDemo.vue | 134 ++++++++++++++++++ .../tabs/src/stories/tabs.stories.ts | 41 ++++++ packages/components/tabs/src/tab-content.ts | 65 +++++++-- packages/components/tabs/src/tab-list.ts | 80 +++++------ packages/components/tabs/src/tab-trigger.ts | 99 ++++++++++++- packages/components/tabs/src/tabs.ts | 129 ++++++++++------- packages/core/use-composable/src/index.ts | 2 + .../use-composable/src/useArrowNavigation.ts | 130 +++++++++++++++++ .../use-composable/src/usePrimitiveElement.ts | 12 ++ playground/vue3/package.json | 1 + playground/vue3/src/pages/index.vue | 4 + playground/vue3/src/pages/tabs.vue | 7 + pnpm-lock.yaml | 93 ++++++++++-- 15 files changed, 680 insertions(+), 125 deletions(-) create mode 100644 packages/components/tabs/src/stories/TabsDemo.vue create mode 100644 packages/components/tabs/src/stories/tabs.stories.ts create mode 100644 packages/core/use-composable/src/useArrowNavigation.ts create mode 100644 packages/core/use-composable/src/usePrimitiveElement.ts create mode 100644 playground/vue3/src/pages/tabs.vue diff --git a/package.json b/package.json index 6b9472e6b..ac7f06671 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,9 @@ "clean:dist": "rimraf 'packages/**/dist' 'playground/**/dist'", "clean:dts": "rimraf 'playground/vue3/src/components.d.ts' 'playground/vue3/src/auto-imports.d.ts' 'playground/nuxt3/.nuxt'" }, + "dependencies": { + "@vueuse/core": "^10.2.1" + }, "devDependencies": { "@egoist/tailwindcss-icons": "^1.1.0", "@iconify-json/ph": "^1.1.5", @@ -37,6 +40,7 @@ "@oku-ui/label": "workspace:^", "@oku-ui/progress": "workspace:^", "@oku-ui/separator": "workspace:^", + "@oku-ui/tabs": "workspace:^", "@oku-ui/toggle": "workspace:^", "@storybook/addon-essentials": "^7.0.26", "@storybook/addon-interactions": "^7.0.26", diff --git a/packages/components/tabs/src/index.ts b/packages/components/tabs/src/index.ts index 7648ba21f..e28afb251 100644 --- a/packages/components/tabs/src/index.ts +++ b/packages/components/tabs/src/index.ts @@ -3,5 +3,7 @@ export { OkuTabList } from './tab-list' export { OkuTabTrigger } from './tab-trigger' export { OkuTabContent } from './tab-content' -export type { TabsProps } from './tabs' +export type { TabsProps, TabsProvideValue } from './tabs' export { type TabListProps } from './tab-list' +export { type TabsTriggerProps } from './tab-trigger' +export { type TabsContentProps } from './tab-content' diff --git a/packages/components/tabs/src/stories/TabsDemo.vue b/packages/components/tabs/src/stories/TabsDemo.vue new file mode 100644 index 000000000..ac3fe5aae --- /dev/null +++ b/packages/components/tabs/src/stories/TabsDemo.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/packages/components/tabs/src/stories/tabs.stories.ts b/packages/components/tabs/src/stories/tabs.stories.ts new file mode 100644 index 000000000..f776aee34 --- /dev/null +++ b/packages/components/tabs/src/stories/tabs.stories.ts @@ -0,0 +1,41 @@ +import type { Meta, StoryObj } from '@storybook/vue3' + +import type { OkuTabs } from '../tabs' +import OkuTabsComponent from './TabsDemo.vue' + +const meta = { + title: 'Components/Tabs', + component: OkuTabsComponent, + args: { + orientation: 'horizontal', + defaultValue: 'tab1', + }, + tags: ['autodocs'], +} satisfies Meta> + +export default meta +type Story = StoryObj + +export const Styled: Story = { + render: (args: any) => ({ + components: { OkuTabsComponent }, + setup() { + return { args } + }, + template: ` + + `, + }), +} + +export const Indeterminate: Story = { + render: (args: any) => ({ + components: { OkuTabsComponent }, + setup() { + return { args } + }, + template: ` + + `, + }), +} diff --git a/packages/components/tabs/src/tab-content.ts b/packages/components/tabs/src/tab-content.ts index b2004a4df..ad4e02119 100644 --- a/packages/components/tabs/src/tab-content.ts +++ b/packages/components/tabs/src/tab-content.ts @@ -1,30 +1,71 @@ -import { type PropType, defineComponent, h } from 'vue' +import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' +import { type PropType, computed, defineComponent, h, inject } from 'vue' +import type { TabsProvideValue } from './tabs' +import { TABS_INJECTION_KEY } from './tabs' + +/* ------------------------------------------------------------------------------------------------- + * TabTrigger + * ----------------------------------------------------------------------------------------------- */ const TAB_CONTENT_NAME = 'TabContent' as const +interface TabsContentProps extends PrimitiveProps { + value?: string + forceMount?: boolean +} + const TabContent = defineComponent({ name: TAB_CONTENT_NAME, inheritAttrs: false, props: { - activeTab: { - type: String as PropType, - required: true, - }, value: { type: String as PropType, required: true, }, + forceMount: { + type: Boolean as PropType, + default: false, + }, }, setup(props, { slots }) { - const slot = slots.default ? slots.default() : [] - return () => { - if (props.activeTab === props.value) - return h('div', { class: 'tab-content' }, slot) - else return null - } + const injectedValue = inject(TABS_INJECTION_KEY) + + const dataState = computed<'active' | 'inactive'>(() => { + return injectedValue?.modelValue?.value === props.value + ? 'active' + : 'inactive' + }) + + const shouldRender = computed(() => { + return ( + injectedValue?.modelValue?.value === props.value || props.forceMount + ) + }) + + return () => + h('div', [ + shouldRender.value + ? h( + Primitive.div, + { + 'vIf': injectedValue?.modelValue?.value === props.value, + 'role': 'tab-content', + 'data-state': dataState.value, + 'data-orientation': injectedValue?.orientation, + 'tabindex': '0', + }, + slots.default && slots.default(), + ) + : null, + ]) }, }) -const OkuTabContent = TabContent as typeof TabContent +type _TabsProps = MergeProps + +const OkuTabContent = TabContent as typeof TabContent & +(new () => { $props: _TabsProps }) export { OkuTabContent } + +export type { TabsContentProps } diff --git a/packages/components/tabs/src/tab-list.ts b/packages/components/tabs/src/tab-list.ts index 59d8b40c4..2a88561b8 100644 --- a/packages/components/tabs/src/tab-list.ts +++ b/packages/components/tabs/src/tab-list.ts @@ -1,5 +1,13 @@ -import type { MergeProps, PrimitiveProps } from '@oku-ui/primitive' -import { type PropType, defineComponent, h } from 'vue' +import { + type MergeProps, + Primitive, + type PrimitiveProps, +} from '@oku-ui/primitive' +import type { PropType } from 'vue' +import { defineComponent, h, inject, onMounted } from 'vue' +import { usePrimitiveElement } from '@oku-ui/use-composable' +import type { TabsProvideValue } from './tabs' +import { TABS_INJECTION_KEY } from './tabs' /* ------------------------------------------------------------------------------------------------- * TabList @@ -8,55 +16,41 @@ import { type PropType, defineComponent, h } from 'vue' const TAB_LIST_NAME = 'TabList' as const interface TabListProps extends PrimitiveProps { - /** - * The active tab value. - * @default 'tab1' - * @type string - * @example - * ```vue - * - * - * // ... - * - * - * ``` - * @see link-to-oku-docs/tab - * */ - activeTab: string - /** - * The callback function that is called when the tab value changes. - * @default () => {} - * @type (value: string) => void - * @example - * ```vue - * console.log(value)}> - * console.log(value)}> - // ... - * - * - * ``` - * @see link-to-oku-docs/tab - * */ - onChange: (value: string) => void + loop?: boolean } const TabList = defineComponent({ name: TAB_LIST_NAME, inheritAttrs: false, props: { - activeTab: { - type: String as PropType, - required: true, - }, - onChange: { - type: Function as PropType<(value: string) => void>, - required: true, + loop: { + type: Boolean as PropType, + default: true, }, }, - setup(_, { slots }) { - const slot = slots.default ? slots.default() : [] - - return () => h('div', { 'data-attr': 'tab-list' }, slot) + setup(props, { slots }) { + const injectedValue = inject(TABS_INJECTION_KEY) + const { primitiveElement, currentElement: parentElement } + = usePrimitiveElement() + + onMounted(() => { + injectedValue!.parentElement.value = parentElement.value + injectedValue!.loop = props.loop + }) + + return () => + h( + Primitive.div, + { + 'role': 'tab-list', + 'ref': primitiveElement, + 'aria-orientation': injectedValue?.orientation, + 'tabindex': 0, + 'data-orientation': injectedValue?.orientation, + 'style': 'outline: none', + }, + slots.default && slots.default(), + ) }, }) diff --git a/packages/components/tabs/src/tab-trigger.ts b/packages/components/tabs/src/tab-trigger.ts index 676113f25..d7ab86609 100644 --- a/packages/components/tabs/src/tab-trigger.ts +++ b/packages/components/tabs/src/tab-trigger.ts @@ -1,7 +1,23 @@ -import { type PropType, defineComponent, h } from 'vue' +import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' +import { type PropType, computed, defineComponent, h, inject } from 'vue' +import { + useArrowNavigation, + usePrimitiveElement, +} from '@oku-ui/use-composable' +import type { TabsProvideValue } from './tabs' +import { TABS_INJECTION_KEY } from './tabs' + +/* ------------------------------------------------------------------------------------------------- + * TabTrigger + * ----------------------------------------------------------------------------------------------- */ const TAB_TRIGGER_NAME = 'TabTrigger' as const +interface TabsTriggerProps extends PrimitiveProps { + value: string + disabled: boolean +} + const TabTrigger = defineComponent({ name: TAB_TRIGGER_NAME, inheritAttrs: false, @@ -10,18 +26,87 @@ const TabTrigger = defineComponent({ type: String as PropType, required: true, }, + disabled: { + type: Boolean as PropType, + default: false, + }, }, - setup(props, { slots, emit }) { - const handleClick = () => { - emit('change', props.value) + setup(props, { slots }) { + const injectedValue = inject(TABS_INJECTION_KEY) + const { primitiveElement, currentElement } = usePrimitiveElement() + + function changeTab(value: string) { + injectedValue?.changeModelValue(value) + } + + function handleKeydown(e: KeyboardEvent) { + if (!injectedValue?.parentElement.value || !currentElement.value) + return + const newSelectedElement = useArrowNavigation( + e, + currentElement.value, + injectedValue?.parentElement.value, + { + arrowKeyOptions: injectedValue?.orientation, + loop: injectedValue?.loop, + }, + ) + + if (newSelectedElement) { + newSelectedElement.focus() + injectedValue!.currentFocusedElement!.value = newSelectedElement + + if (injectedValue?.activationMode === 'automatic') { + changeTab( + newSelectedElement.getAttribute('data-oku-ui-tab-value')!, + ) + } + } } - const slot = slots.default ? slots.default() : [] + const getTabIndex = computed(() => { + if (!injectedValue?.currentFocusedElement?.value) { + return injectedValue?.modelValue?.value === props.value ? '0' : '-1' + } + else { + return injectedValue?.currentFocusedElement?.value + === currentElement.value + ? '0' + : '-1' + } + }) - return () => h('button', { onClick: handleClick }, slot) + return () => + h( + Primitive.button, + { + 'ref': primitiveElement, + 'type': Primitive.button, + 'role': 'tab', + 'aria-selected': + injectedValue?.modelValue?.value === props.value ? 'true' : 'false', + 'data-state': + injectedValue?.modelValue?.value === props.value + ? 'active' + : 'inactive', + 'disabled': props.disabled, + 'data-disabled': props.disabled ? '' : undefined, + 'tabindex': getTabIndex.value, + 'data-orientation': injectedValue?.orientation, + 'data-oku-ui-collection-item': true, + 'data-oku-ui-tab-value': props.value, + 'onClick': () => changeTab(props.value!), + 'onKeydown': handleKeydown, + }, + slots.default && slots.default(), + ) }, }) -const OkuTabTrigger = TabTrigger as typeof TabTrigger +type _TabsProps = MergeProps + +const OkuTabTrigger = TabTrigger as typeof TabTrigger & (new () => { $props: _TabsProps }) export { OkuTabTrigger } + +export type { TabsTriggerProps } diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts index ffd00d6d7..613c2b1d1 100644 --- a/packages/components/tabs/src/tabs.ts +++ b/packages/components/tabs/src/tabs.ts @@ -1,7 +1,7 @@ -import type { MergeProps, PrimitiveProps } from '@oku-ui/primitive' -import { type PropType, defineComponent, h, ref } from 'vue' -import { OkuTabContent } from './tab-content' -import { OkuTabList } from './tab-list' +import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' +import { defineComponent, h, provide, ref } from 'vue' +import type { InjectionKey, PropType, Ref } from 'vue' +import { useVModel } from '@vueuse/core' /* ------------------------------------------------------------------------------------------------- * Tabs @@ -9,6 +9,9 @@ import { OkuTabList } from './tab-list' const TAB_NAME = 'TAB' as const +type Orientation = 'horizontal' | 'vertical' +type Direction = 'ltr' | 'rtl' +type ActivationMode = 'automatic' | 'manual' interface TabsProps extends PrimitiveProps { /** * The default value of the tab. @@ -46,69 +49,91 @@ interface TabsProps extends PrimitiveProps { * ``` * @see link-to-oku-docs/tab * */ - orientation?: 'horizontal' | 'vertical' + orientation?: Orientation + dir?: Direction + activationMode?: ActivationMode + modelValue?: string } +interface TabsProvideValue { + modelValue?: Readonly> + currentFocusedElement?: Ref + changeModelValue: (value: string) => void + parentElement: Ref + orientation: Orientation + dir: Direction + activationMode: ActivationMode + loop: boolean +} + +const TABS_INJECTION_KEY = Symbol(`${TAB_NAME} provide key`) as InjectionKey + const Tabs = defineComponent({ name: TAB_NAME, inheritAttrs: false, props: { defaultValue: { type: String as PropType, - default: 'tab1', - }, - onValueChange: { - type: Function as PropType<(value: string) => void>, - default: () => {}, + default: undefined, }, orientation: { - type: String as PropType<'horizontal' | 'vertical'>, + type: String as PropType, default: 'horizontal', }, + dir: { + type: String as PropType, + default: 'ltr', + required: false, + }, + activationMode: { + type: String as PropType, + default: 'automatic', + required: false, + }, + modelValue: { + type: String as PropType, + required: false, + }, + onValueChange: { + type: Function as PropType<(value: string) => void>, + required: false, + }, }, - setup(props, { slots }) { - const activeTab = ref(props.defaultValue) + emits: ['update:modelValue'], + setup(props, { slots, emit }) { + const parentElementRef = ref() + const currentFocusedElementRef = ref() - const handleTabChange = (value: string) => { - activeTab.value = value - props.onValueChange?.(value) - } + const modelValue = useVModel(props, 'modelValue', emit, { + defaultValue: props.defaultValue, + passive: true, + }) - return () => { - const tabListSlot = slots.default - ? slots.default({ activeTab: activeTab.value }) - : [] - const tabContentSlot = slots.tabContent - ? slots.tabContent({ activeTab: activeTab.value }) - : [] + provide(TABS_INJECTION_KEY, { + modelValue, + changeModelValue: (value: string) => { + modelValue.value = value + if (value && props.onValueChange) + props.onValueChange(value) + }, + currentFocusedElement: currentFocusedElementRef, + parentElement: parentElementRef, + orientation: props.orientation, + dir: props.dir, + loop: true, + activationMode: props.activationMode, + }) - return h('div', {}, [ - h( - // TODO: fix this - // @ts-expect-error - OkuTabList, - { - activeTab: activeTab.value, - onChange: handleTabChange, - }, - tabListSlot, - ), - h( - // TODO: fix this - // @ts-expect-error - OkuTabContent, - { - activeTab: activeTab.value, - }, - tabContentSlot.map(contentVNode => - h(OkuTabContent, { - activeTab: activeTab.value, - value: contentVNode.props?.value, - }), - ), - ), - ]) - } + return () => + h( + Primitive.div, + { + 'dir': props.dir, + 'data-orientation': props.orientation, + 'role': 'tab-group', + }, + slots.default && slots.default(), + ) }, }) @@ -116,6 +141,6 @@ type _TabsProps = MergeProps const OkuTabs = Tabs as typeof Tabs & (new () => { $props: _TabsProps }) -export { OkuTabs } +export { OkuTabs, TABS_INJECTION_KEY, TabsProvideValue } export type { TabsProps } diff --git a/packages/core/use-composable/src/index.ts b/packages/core/use-composable/src/index.ts index 77cc1079b..513bd2611 100644 --- a/packages/core/use-composable/src/index.ts +++ b/packages/core/use-composable/src/index.ts @@ -6,3 +6,5 @@ export { useRef } from './useRef' export { unrefElement } from './unrefElement' export { useId } from './useId' export type { MaybeComputedElementRef } from './unrefElement' +export { usePrimitiveElement } from './usePrimitiveElement' +export { useArrowNavigation } from './useArrowNavigation' diff --git a/packages/core/use-composable/src/useArrowNavigation.ts b/packages/core/use-composable/src/useArrowNavigation.ts new file mode 100644 index 000000000..7b6813d8b --- /dev/null +++ b/packages/core/use-composable/src/useArrowNavigation.ts @@ -0,0 +1,130 @@ +export type ArrowKeyOptions = 'horizontal' | 'vertical' | 'both' +type Direction = 'ltr' | 'rtl' + +export interface ArrowNavigationOptions { + /** + * The arrow key options to allow navigation + * + * @default "both" + */ + arrowKeyOptions?: ArrowKeyOptions + + /** + * The attribute name to find the collection items in the parent element. + * + * @default "data-oku-ui-collection-item" + */ + attributeName?: string + + /** + * The parent element where contains all the collection items, this will collect every item to be used when nav + * It will be ignored if attributeName is provided + * + * @default [] + */ + itemsArray?: HTMLElement[] + + /** + * Allow loop navigation. If false, it will stop at the first and last element + * + * @default true + */ + loop?: boolean + + /** + * The orientation of the collection + * + * @default "ltr" + */ + dir?: Direction + + /** + * Prevent the scroll when navigating. This happens when the direction of the + * key matches the scroll direction of any ancestor scrollable elements. + * + * @default true + */ + preventScroll?: boolean +} + +export function useArrowNavigation( + e: KeyboardEvent, + currentElement: HTMLElement, + parentElement: HTMLElement | undefined, + options: ArrowNavigationOptions = {}, +): HTMLElement | null { + const { + arrowKeyOptions = 'both', + attributeName = 'data-oku-ui-collection-item', + itemsArray = [], + loop = true, + dir = 'ltr', + preventScroll = true, + } = options + + const [right, left, up, down] = [ + e.key === 'ArrowRight', + e.key === 'ArrowLeft', + e.key === 'ArrowUp', + e.key === 'ArrowDown', + ] + const goingVertical = up || down + const goingHorizontal = right || left + if ( + (!goingVertical && !goingHorizontal) + || (arrowKeyOptions === 'vertical' && goingHorizontal) + || (arrowKeyOptions === 'horizontal' && goingVertical) + ) + return null + + const allCollectionItems: HTMLElement[] = parentElement + ? Array.from(parentElement.querySelectorAll(`[${attributeName}]`)) + : itemsArray + + if (!allCollectionItems.length) + return null + + if (preventScroll) + e.preventDefault() + + const goForward = goingVertical ? down : dir === 'ltr' ? right : left + + return findNextFocusableElement(allCollectionItems, currentElement, { + goForward, + loop, + }) +} + +function findNextFocusableElement( + elements: HTMLElement[], + currentElement: HTMLElement, + { goForward, loop }: { goForward: boolean; loop?: boolean }, + iterations = elements.length, +): HTMLElement | null { + if (--iterations === 0) + return null + + const index = elements.indexOf(currentElement) + const newIndex = goForward ? index + 1 : index - 1 + + if (!loop && (newIndex < 0 || newIndex >= elements.length)) + return null + + const adjustedNewIndex = (newIndex + elements.length) % elements.length + const candidate = elements[adjustedNewIndex] + if (!candidate) + return null + + const isDisabled + = candidate.hasAttribute('disabled') + && candidate.getAttribute('disabled') !== 'false' + if (isDisabled) { + return findNextFocusableElement( + elements, + candidate, + { goForward, loop }, + iterations, + ) + } + return candidate +} diff --git a/packages/core/use-composable/src/usePrimitiveElement.ts b/packages/core/use-composable/src/usePrimitiveElement.ts new file mode 100644 index 000000000..d9601c7c8 --- /dev/null +++ b/packages/core/use-composable/src/usePrimitiveElement.ts @@ -0,0 +1,12 @@ +import { computed, ref } from 'vue' +import { unrefElement } from './unrefElement' + +export function usePrimitiveElement() { + const primitiveElement = ref() + const currentElement = computed(() => unrefElement(primitiveElement)) + + return { + primitiveElement, + currentElement, + } +} diff --git a/playground/vue3/package.json b/playground/vue3/package.json index 001dfa67e..b6e336c1f 100644 --- a/playground/vue3/package.json +++ b/playground/vue3/package.json @@ -17,6 +17,7 @@ "@oku-ui/label": "workspace:^", "@oku-ui/progress": "workspace:^", "@oku-ui/separator": "workspace:^", + "@oku-ui/tabs": "workspace:^", "vite-plugin-pages": "^0.31.0", "vue": "^3.3.4", "vue-router": "^4.2.4" diff --git a/playground/vue3/src/pages/index.vue b/playground/vue3/src/pages/index.vue index b98cc19f9..fec797b26 100644 --- a/playground/vue3/src/pages/index.vue +++ b/playground/vue3/src/pages/index.vue @@ -32,6 +32,10 @@ const pages: Page[] = [ name: 'OkuToggle', path: '/toggle', }, + { + name: 'OkuTabs', + path: '/tabs', + }, ] diff --git a/playground/vue3/src/pages/tabs.vue b/playground/vue3/src/pages/tabs.vue new file mode 100644 index 000000000..01ce69ffd --- /dev/null +++ b/playground/vue3/src/pages/tabs.vue @@ -0,0 +1,7 @@ + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cee0501d..6cc613bee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -12,6 +12,10 @@ overrides: importers: .: + dependencies: + '@vueuse/core': + specifier: ^10.2.1 + version: 10.2.1(vue@3.3.4) devDependencies: '@egoist/tailwindcss-icons': specifier: ^1.1.0 @@ -40,6 +44,9 @@ importers: '@oku-ui/separator': specifier: workspace:^ version: link:packages/components/separator + '@oku-ui/tabs': + specifier: workspace:^ + version: link:packages/components/tabs '@oku-ui/toggle': specifier: workspace:^ version: link:packages/components/toggle @@ -141,7 +148,7 @@ importers: version: 1.2.1 unplugin-vue-macros: specifier: ^2.3.3 - version: 2.3.3(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4) + version: 2.3.3(@vueuse/core@10.2.1)(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4) vite: specifier: 4.3.5 version: 4.3.5(@types/node@18.16.19) @@ -294,6 +301,28 @@ importers: specifier: workspace:^ version: link:../../tsconfig + packages/components/tabs: + dependencies: + '@oku-ui/primitive': + specifier: workspace:^ + version: link:../../core/primitive + '@oku-ui/provide': + specifier: workspace:^ + version: link:../../core/provide + '@oku-ui/use-composable': + specifier: workspace:^ + version: link:../../core/use-composable + '@oku-ui/utils': + specifier: workspace:^ + version: link:../../core/utils + vue: + specifier: ^3.3.4 + version: 3.3.4 + devDependencies: + tsconfig: + specifier: workspace:^ + version: link:../../tsconfig + packages/components/toggle: dependencies: '@oku-ui/primitive': @@ -427,6 +456,9 @@ importers: '@oku-ui/separator': specifier: workspace:^ version: link:../../packages/components/separator + '@oku-ui/tabs': + specifier: workspace:^ + version: link:../../packages/components/tabs vite-plugin-pages: specifier: ^0.31.0 version: 0.31.0(vite@4.3.5) @@ -445,7 +477,7 @@ importers: version: 5.1.6 unplugin-auto-import: specifier: ^0.16.6 - version: 0.16.6(rollup@3.21.0) + version: 0.16.6(@vueuse/core@10.2.1)(rollup@3.21.0) unplugin-vue-components: specifier: ^0.25.1 version: 0.25.1(rollup@3.21.0)(vue@3.3.4) @@ -4323,7 +4355,7 @@ packages: ts-dedent: 2.2.0 type-fest: 2.19.0 vue: 3.3.4 - vue-component-type-helpers: 1.8.4 + vue-component-type-helpers: 1.8.5 transitivePeerDependencies: - encoding - supports-color @@ -4638,6 +4670,9 @@ packages: /@types/unist@2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + /@types/web-bluetooth@0.0.17: + resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} + /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true @@ -5108,7 +5143,7 @@ packages: vue: 3.3.4 dev: true - /@vue-macros/define-models@1.0.8(rollup@3.21.0)(vue@3.3.4): + /@vue-macros/define-models@1.0.8(@vueuse/core@10.2.1)(rollup@3.21.0)(vue@3.3.4): resolution: {integrity: sha512-tL8A49Fz34m8+63uoJYS/OpB+gApu49ZX4kZ0LY0daZ1sFhnzexNihljaGacoUQ3GIXelPwlJ/yqxv8KM8zPQQ==} engines: {node: '>=16.14.0'} peerDependencies: @@ -5118,6 +5153,7 @@ packages: optional: true dependencies: '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) + '@vueuse/core': 10.2.1(vue@3.3.4) ast-walker-scope: 0.4.2 unplugin: 1.3.2 transitivePeerDependencies: @@ -5460,6 +5496,28 @@ packages: - typescript dev: true + /@vueuse/core@10.2.1(vue@3.3.4): + resolution: {integrity: sha512-c441bfMbkAwTNwVRHQ0zdYZNETK//P84rC01aP2Uy/aRFCiie9NE/k9KdIXbno0eDYP5NPUuWv0aA/I4Unr/7w==} + dependencies: + '@types/web-bluetooth': 0.0.17 + '@vueuse/metadata': 10.2.1 + '@vueuse/shared': 10.2.1(vue@3.3.4) + vue-demi: 0.14.5(vue@3.3.4) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + /@vueuse/metadata@10.2.1: + resolution: {integrity: sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==} + + /@vueuse/shared@10.2.1(vue@3.3.4): + resolution: {integrity: sha512-QWHq2bSuGptkcxx4f4M/fBYC3Y8d3M2UYyLsyzoPgEoVzJURQ0oJeWXu79OiLlBb8gTKkqe4mO85T/sf39mmiw==} + dependencies: + vue-demi: 0.14.5(vue@3.3.4) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + /@webassemblyjs/ast@1.11.5: resolution: {integrity: sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==} dependencies: @@ -13510,7 +13568,7 @@ packages: engines: {node: '>= 0.8'} dev: true - /unplugin-auto-import@0.16.6(rollup@3.21.0): + /unplugin-auto-import@0.16.6(@vueuse/core@10.2.1)(rollup@3.21.0): resolution: {integrity: sha512-M+YIITkx3C/Hg38hp8HmswP5mShUUyJOzpifv7RTlAbeFlO2Tyw0pwrogSSxnipHDPTtI8VHFBpkYkNKzYSuyA==} engines: {node: '>=14'} peerDependencies: @@ -13524,6 +13582,7 @@ packages: dependencies: '@antfu/utils': 0.7.5 '@rollup/pluginutils': 5.0.2(rollup@3.21.0) + '@vueuse/core': 10.2.1(vue@3.3.4) fast-glob: 3.3.0 local-pkg: 0.4.3 magic-string: 0.30.1 @@ -13600,7 +13659,7 @@ packages: - vue dev: true - /unplugin-vue-macros@2.3.3(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4): + /unplugin-vue-macros@2.3.3(@vueuse/core@10.2.1)(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4): resolution: {integrity: sha512-+aE2BIH2CZ1LVI/JdPxn8QPp386ZaRa8/q9I/aXnCav7UfhMiq7XW5GbpqWUP/yY/rjF+rdfXdkvUKUMTxy7mw==} engines: {node: '>=16.14.0'} peerDependencies: @@ -13610,7 +13669,7 @@ packages: '@vue-macros/chain-call': 0.0.3(rollup@3.21.0)(vue@3.3.4) '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) '@vue-macros/define-emit': 0.1.8(vue@3.3.4) - '@vue-macros/define-models': 1.0.8(rollup@3.21.0)(vue@3.3.4) + '@vue-macros/define-models': 1.0.8(@vueuse/core@10.2.1)(rollup@3.21.0)(vue@3.3.4) '@vue-macros/define-prop': 0.1.10(vue@3.3.4) '@vue-macros/define-props': 1.0.10(@vue-macros/reactivity-transform@0.3.12)(rollup@3.21.0)(vue@3.3.4) '@vue-macros/define-props-refs': 1.1.2(rollup@3.21.0)(vue@3.3.4) @@ -14217,10 +14276,24 @@ packages: resolution: {integrity: sha512-iGdlqtajmiqed8ptURKPJ/Olz0/mwripVZszg6tygfZSIL9kYFPJTNY6+Q6OjWGznl2L06vxG5HvNvAnWrnzbg==} dev: true - /vue-component-type-helpers@1.8.4: - resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==} + /vue-component-type-helpers@1.8.5: + resolution: {integrity: sha512-SBNsskF7L5x604V1BN4ZzdTtWgCqo5cfl//YuBXtc3LLyPdFRqUeJn2Q+FPNmCtl23LBT2tH79M/uv13fL0MgQ==} dev: true + /vue-demi@0.14.5(vue@3.3.4): + resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.3.4 + /vue-devtools-stub@0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} dev: true From 8751a8287b2e5c5c671c4524bd1b02153c71442d Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 06:14:54 +0300 Subject: [PATCH 03/13] fix: merge --- package.json | 2 +- packages/core/use-composable/src/index.ts | 1 - pnpm-lock.yaml | 326 +--------------------- 3 files changed, 4 insertions(+), 325 deletions(-) diff --git a/package.json b/package.json index fcb1c9940..9a63e35e3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "primitives", "type": "module", "version": "0.3.0", - "packageManager": "pnpm@8.6.6", + "packageManager": "pnpm@8.6.9", "repository": "oku-ui/primitives", "engines": { "node": ">=18" diff --git a/packages/core/use-composable/src/index.ts b/packages/core/use-composable/src/index.ts index 2d710e33a..2c7d34f8b 100644 --- a/packages/core/use-composable/src/index.ts +++ b/packages/core/use-composable/src/index.ts @@ -11,4 +11,3 @@ export type { MaybeComputedElementRef } from './unrefElement' export { usePrimitiveElement } from './usePrimitiveElement' export { useArrowNavigation } from './useArrowNavigation' export { computedEager, syncRef } -\ \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d054a20e9..f518bc91e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -170,12 +170,9 @@ importers: unbuild: specifier: ^1.2.1 version: 1.2.1 - unplugin-vue-macros: - specifier: ^2.3.3 - version: 2.3.3(@vueuse/core@10.2.1)(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4) vite: specifier: 4.3.5 - version: 4.3.5(@types/node@18.16.18) + version: 4.3.5(@types/node@18.16.19) vite-plugin-dts: specifier: ^3.3.0 version: 3.3.0(rollup@3.21.0)(typescript@5.1.6)(vite@4.3.5) @@ -585,7 +582,7 @@ importers: version: 0.25.1(rollup@3.21.0)(vue@3.3.4) vite: specifier: 4.3.5 - version: 4.3.5(@types/node@18.16.18) + version: 4.3.5(@types/node@18.16.19) vue-tsc: specifier: ^1.8.5 version: 1.8.5(typescript@5.1.6) @@ -4855,7 +4852,6 @@ packages: /@types/web-bluetooth@0.0.17: resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} - dev: false /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} @@ -5217,265 +5213,6 @@ packages: '@volar/source-map': 1.8.0 dev: true - /@volar/source-map@1.8.0: - resolution: {integrity: sha512-d35aV0yFkIrkynRSKgrN5hgbMv6ekkFvcJsJGmOZ8UEjqLStto9zq7RSvpp6/PZ7/pa4Gn1f6K1qDt0bq0oUew==} - dependencies: - muggle-string: 0.3.1 - dev: true - - /@volar/typescript@1.8.0: - resolution: {integrity: sha512-T/U1XLLhXv6tNr40Awznfc6QZWizSL99t6M0DeXtIMbnvSCqjjCVRnwlsq+DK9C1RlO3k8+i0Z8iJn7O1GGtoA==} - dependencies: - '@volar/language-core': 1.8.0 - dev: true - - /@vue-macros/api@0.7.3(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-nxDltgnMqi0yX0eAL1iXPgWE6XrgJnghbdXhEf2qIYk6dvLUu3C3ECsKpfkZUC7LDVB0lQTlGSaTS1amm5Sd0w==} - engines: {node: '>=16.14.0'} - dependencies: - '@babel/types': 7.22.5 - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/api@0.7.3(rollup@3.26.2)(vue@3.3.4): - resolution: {integrity: sha512-nxDltgnMqi0yX0eAL1iXPgWE6XrgJnghbdXhEf2qIYk6dvLUu3C3ECsKpfkZUC7LDVB0lQTlGSaTS1amm5Sd0w==} - engines: {node: '>=16.14.0'} - dependencies: - '@babel/types': 7.22.5 - '@vue-macros/common': 1.4.1(rollup@3.26.2)(vue@3.3.4) - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/better-define@1.6.4(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-hHjVj6sjo1AGkPJ9wqBUHlpcHUMUfv//sPWirFbU89MVK4hxNM13THQ74GqzwmJgqLJ1mW0NQSkn3PMnzaaRhg==} - engines: {node: '>=16.14.0'} - dependencies: - '@vue-macros/api': 0.7.3(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/chain-call@0.0.3(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-eeFHYc/fMswvBnKDCIVwNyZIuvU4DaMXYcS1Qrw6Tv69w5swdk/vBm4Ii1b9OjPjgRPg8XWQK5EauN+6sHjh+w==} - engines: {node: '>=16.14.0'} - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/common@1.4.1(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-guxdL0TrAPRaRtbR5iWMkX9ojcyQQ0NBVGvl9ZSxk9ugArQB1z3dCyTCirhHAo5GJZBFJ8FlrqNmpVspZV0MEw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - peerDependenciesMeta: - vue: - optional: true - dependencies: - '@babel/types': 7.22.5 - '@rollup/pluginutils': 5.0.2(rollup@3.21.0) - '@vue/compiler-sfc': 3.3.4 - ast-kit: 0.6.6(rollup@3.21.0) - local-pkg: 0.4.3 - magic-string-ast: 0.1.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/common@1.4.1(rollup@3.26.2)(vue@3.3.4): - resolution: {integrity: sha512-guxdL0TrAPRaRtbR5iWMkX9ojcyQQ0NBVGvl9ZSxk9ugArQB1z3dCyTCirhHAo5GJZBFJ8FlrqNmpVspZV0MEw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - peerDependenciesMeta: - vue: - optional: true - dependencies: - '@babel/types': 7.22.5 - '@rollup/pluginutils': 5.0.2(rollup@3.26.2) - '@vue/compiler-sfc': 3.3.4 - ast-kit: 0.6.6(rollup@3.26.2) - local-pkg: 0.4.3 - magic-string-ast: 0.1.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/define-emit@0.1.8(vue@3.3.4): - resolution: {integrity: sha512-psQtZ9Kwyp8/c4DWRTMehyL7yWycTn7Xz1EP7zDrVBO6oWy+CyvcZaD9xswoj3rqHI+fXSG3unb71T5bNzDuYQ==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/api': 0.7.3(rollup@3.26.2)(vue@3.3.4) - '@vue-macros/common': 1.4.1(rollup@3.26.2)(vue@3.3.4) - rollup: 3.26.2 - unplugin: 1.3.2 - vue: 3.3.4 - dev: true - - /@vue-macros/define-models@1.0.8(@vueuse/core@10.2.1)(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-tL8A49Fz34m8+63uoJYS/OpB+gApu49ZX4kZ0LY0daZ1sFhnzexNihljaGacoUQ3GIXelPwlJ/yqxv8KM8zPQQ==} - engines: {node: '>=16.14.0'} - peerDependencies: - '@vueuse/core': '>=9.0.0' - peerDependenciesMeta: - '@vueuse/core': - optional: true - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - '@vueuse/core': 10.2.1(vue@3.3.4) - ast-walker-scope: 0.4.2 - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/define-prop@0.1.10(vue@3.3.4): - resolution: {integrity: sha512-zuATgnqUIKHykV9hpezrnQnUycrTiKLAoynkAqLJM9NNYLFAfjp/nqLFLqjkL7NcZjGihoKYzHmxCej3mvkjOg==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/api': 0.7.3(rollup@3.26.2)(vue@3.3.4) - '@vue-macros/common': 1.4.1(rollup@3.26.2)(vue@3.3.4) - rollup: 3.26.2 - unplugin: 1.3.2 - vue: 3.3.4 - dev: true - - /@vue-macros/define-props-refs@1.1.2(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-a7WECgZV8uoa0NLkKs7jkk+Y7DYCwEhQHKwmoLyL7azb17ntXcPFNWB+muGTFF7jXqZUBF9UgC1oUNVPRdeYaw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/define-props@1.0.10(@vue-macros/reactivity-transform@0.3.12)(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-/y37j5pwuqxKfAbgIsD/4Sxmn1q7DWR0owsUeW8wIcMBFcUTdk1ikyUMgv+nWPGsNytW7d9uymtqIe/DzAYc9A==} - engines: {node: '>=16.14.0'} - peerDependencies: - '@vue-macros/reactivity-transform': ^0.3.12 - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/reactivity-transform': 0.3.12(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/define-render@1.3.11(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-qSd4nYTz9r2nefn7NXtWec6n84B7+vi84soSgNA/LVAjgYS1qhl9WwZdBvEy9bLN2f6m4Mxs6egJ6uDVwGbfzQ==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.0.0 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/define-slots@1.0.7(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-9i2uemlGs9rhkU0DM6B6QDZ02d5FKHlY+wF2pLxuQ3+ODTiGJB1CPbSWabgdmSE39wct+YFB3ka4ZyCcbpyeAw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.0.0 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/devtools@0.1.3(vite@4.3.5): - resolution: {integrity: sha512-aQRC9/TfmQajTMbZZ1BJn61rrraQztJqf64JdXRIpotbGR+xufLY/KIyTTB4SgL1pE1eW/ar5FaZTSjMqyVGIg==} - engines: {node: '>=16.14.0'} - peerDependencies: - vite: ^4.0.0 - peerDependenciesMeta: - vite: - optional: true - dependencies: - sirv: 2.0.3 - vite: 4.3.5 - vue: 3.3.4 - dev: true - - /@vue-macros/export-expose@0.0.5(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-T9sxvfb1RKFN5QY9YcK/LrKyY0eou56R/sSkyaLsX2IMVIVQLdKV7aqp1qxZV3O5N+tLSE/C63KuxzI7yQbJQA==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - '@vue/compiler-sfc': 3.3.4 - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/export-props@0.3.10(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-psUlgsSh9ybmcIqJrJszan6nWeB+2ycKoZNyMgQl1ARiy2UrhSxGMWOLBpWFY1Fh6Ihz1hAglWvN7EIQsgGENw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - vue: 3.3.4 - transitivePeerDependencies: - - rollup - dev: true - - /@vue-macros/hoist-static@1.4.4(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-FWMS/1oPferEq8ZlMAU5KVd+DD7Q/JnvYKoFu598huzTt1YmGt3jJE+mvH37qJaZle5C9do9Wp2JXRgq1Bu6fQ==} - engines: {node: '>=16.14.0'} - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - - /@vue-macros/named-template@0.3.11(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-f+JV3AxZsBOUR7bWaLxSeWxDu6WTKWmA9NHG/eDKphnURYeTK1BZozy/dG1qPMcJreB8wdU6Tt5DxsCgSGgEBw==} - engines: {node: '>=16.14.0'} - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - '@vue/compiler-dom': 3.3.4 - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - /@volar/language-core@1.9.0: resolution: {integrity: sha512-+PTRrGanAD2PxqMty0ZC46xhgW5BWzb67RLHhZyB3Im4+eMXsKlYjFUt7Z8ZCwTWQQOnj8NQ6gSgUEoOTwAHrQ==} dependencies: @@ -5694,11 +5431,6 @@ packages: /@vueuse/metadata@10.2.1: resolution: {integrity: sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==} - dev: false - - /@vueuse/metadata@10.2.1: - resolution: {integrity: sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==} - dev: false /@vueuse/shared@10.2.1(vue@3.3.4): resolution: {integrity: sha512-QWHq2bSuGptkcxx4f4M/fBYC3Y8d3M2UYyLsyzoPgEoVzJURQ0oJeWXu79OiLlBb8gTKkqe4mO85T/sf39mmiw==} @@ -5707,7 +5439,6 @@ packages: transitivePeerDependencies: - '@vue/composition-api' - vue - dev: false /@webassemblyjs/ast@1.11.5: resolution: {integrity: sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==} @@ -13804,56 +13535,6 @@ packages: - supports-color dev: true - /unplugin-vue-define-options@1.3.10(rollup@3.21.0)(vue@3.3.4): - resolution: {integrity: sha512-+s+7pEQ+HflSTwBj2fd+83BD7tsai08yzJJkciZlKr9JaYHPNr0t0Rb59PHuxHsfg+QNVBX4qOzYJ+o6ZAHGeQ==} - engines: {node: '>=16.14.0'} - dependencies: - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - ast-walker-scope: 0.4.2 - unplugin: 1.3.2 - transitivePeerDependencies: - - rollup - - vue - dev: true - - /unplugin-vue-macros@2.3.3(@vueuse/core@10.2.1)(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5)(vue@3.3.4): - resolution: {integrity: sha512-+aE2BIH2CZ1LVI/JdPxn8QPp386ZaRa8/q9I/aXnCav7UfhMiq7XW5GbpqWUP/yY/rjF+rdfXdkvUKUMTxy7mw==} - engines: {node: '>=16.14.0'} - peerDependencies: - vue: ^2.7.0 || ^3.2.25 - dependencies: - '@vue-macros/better-define': 1.6.4(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/chain-call': 0.0.3(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/common': 1.4.1(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/define-emit': 0.1.8(vue@3.3.4) - '@vue-macros/define-models': 1.0.8(@vueuse/core@10.2.1)(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/define-prop': 0.1.10(vue@3.3.4) - '@vue-macros/define-props': 1.0.10(@vue-macros/reactivity-transform@0.3.12)(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/define-props-refs': 1.1.2(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/define-render': 1.3.11(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/define-slots': 1.0.7(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/devtools': 0.1.3(vite@4.3.5) - '@vue-macros/export-expose': 0.0.5(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/export-props': 0.3.10(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/hoist-static': 1.4.4(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/named-template': 0.3.11(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/reactivity-transform': 0.3.12(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/setup-block': 0.2.10(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/setup-component': 0.16.11(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/setup-sfc': 0.15.11(rollup@3.21.0)(vue@3.3.4) - '@vue-macros/short-emits': 1.4.2(rollup@3.21.0)(vue@3.3.4) - unplugin: 1.3.2 - unplugin-combine: 0.7.0(esbuild@0.18.11)(rollup@3.21.0)(vite@4.3.5) - unplugin-vue-define-options: 1.3.10(rollup@3.21.0)(vue@3.3.4) - vue: 3.3.4 - transitivePeerDependencies: - - '@vueuse/core' - - esbuild - - rollup - - vite - - webpack - dev: true - /unplugin-vue-router@0.6.4(rollup@3.21.0)(vue-router@4.2.4)(vue@3.3.4): resolution: {integrity: sha512-9THVhhtbVFxbsIibjK59oPwMI1UCxRWRPX7azSkTUABsxovlOXJys5SJx0kd/0oKIqNJuYgkRfAgPuO77SqCOg==} peerDependencies: @@ -14447,7 +14128,6 @@ packages: optional: true dependencies: vue: 3.3.4 - dev: false /vue-devtools-stub@0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} From d95400c0cc5f5f95ec4608b841ace393dd4ce5dc Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 06:16:35 +0300 Subject: [PATCH 04/13] refactor: depencies workspace to latest --- packages/components/tabs/package.json | 8 ++++---- playground/vue3/src/pages/index.vue | 4 ++-- pnpm-lock.yaml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/components/tabs/package.json b/packages/components/tabs/package.json index ed6a62940..a344c1d38 100644 --- a/packages/components/tabs/package.json +++ b/packages/components/tabs/package.json @@ -33,10 +33,10 @@ "vue": "^3.3.4" }, "dependencies": { - "@oku-ui/primitive": "workspace:^", - "@oku-ui/provide": "workspace:^", - "@oku-ui/use-composable": "workspace:^", - "@oku-ui/utils": "workspace:^" + "@oku-ui/primitive": "latest", + "@oku-ui/provide": "latest", + "@oku-ui/use-composable": "latest", + "@oku-ui/utils": "latest" }, "devDependencies": { "tsconfig": "workspace:^" diff --git a/playground/vue3/src/pages/index.vue b/playground/vue3/src/pages/index.vue index 7f0da6e2a..92fceede7 100644 --- a/playground/vue3/src/pages/index.vue +++ b/playground/vue3/src/pages/index.vue @@ -35,11 +35,11 @@ const pages: Page[] = [ { name: 'OkuTabs', path: '/tabs', - }, + }, { name: 'OkuPopper', path: '/popper', - } + }, ] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f518bc91e..9a02cf353 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -397,16 +397,16 @@ importers: packages/components/tabs: dependencies: '@oku-ui/primitive': - specifier: workspace:^ + specifier: latest version: link:../../core/primitive '@oku-ui/provide': - specifier: workspace:^ + specifier: latest version: link:../../core/provide '@oku-ui/use-composable': - specifier: workspace:^ + specifier: latest version: link:../../core/use-composable '@oku-ui/utils': - specifier: workspace:^ + specifier: latest version: link:../../core/utils vue: specifier: ^3.3.4 From 22d13711edc45b1c3a22e7717d6b9efb917f0ed0 Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 06:20:26 +0300 Subject: [PATCH 05/13] fix: default slots --- packages/components/tabs/src/tab-content.ts | 4 +++- packages/components/tabs/src/tab-list.ts | 4 +++- packages/components/tabs/src/tab-trigger.ts | 4 +++- packages/components/tabs/src/tabs.ts | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/components/tabs/src/tab-content.ts b/packages/components/tabs/src/tab-content.ts index ad4e02119..9b9b2768f 100644 --- a/packages/components/tabs/src/tab-content.ts +++ b/packages/components/tabs/src/tab-content.ts @@ -54,7 +54,9 @@ const TabContent = defineComponent({ 'data-orientation': injectedValue?.orientation, 'tabindex': '0', }, - slots.default && slots.default(), + { + default: () => slots.default?.(), + }, ) : null, ]) diff --git a/packages/components/tabs/src/tab-list.ts b/packages/components/tabs/src/tab-list.ts index 2a88561b8..74d56d1d4 100644 --- a/packages/components/tabs/src/tab-list.ts +++ b/packages/components/tabs/src/tab-list.ts @@ -49,7 +49,9 @@ const TabList = defineComponent({ 'data-orientation': injectedValue?.orientation, 'style': 'outline: none', }, - slots.default && slots.default(), + { + default: () => slots.default?.(), + }, ) }, }) diff --git a/packages/components/tabs/src/tab-trigger.ts b/packages/components/tabs/src/tab-trigger.ts index d7ab86609..3d04f1c5e 100644 --- a/packages/components/tabs/src/tab-trigger.ts +++ b/packages/components/tabs/src/tab-trigger.ts @@ -98,7 +98,9 @@ const TabTrigger = defineComponent({ 'onClick': () => changeTab(props.value!), 'onKeydown': handleKeydown, }, - slots.default && slots.default(), + { + default: () => slots.default?.(), + }, ) }, }) diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts index 613c2b1d1..41dc93084 100644 --- a/packages/components/tabs/src/tabs.ts +++ b/packages/components/tabs/src/tabs.ts @@ -132,7 +132,9 @@ const Tabs = defineComponent({ 'data-orientation': props.orientation, 'role': 'tab-group', }, - slots.default && slots.default(), + { + default: () => slots.default?.(), + }, ) }, }) From 85275b38a76b65bf368fe8d8b372cf44dabd4c2c Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 06:29:00 +0300 Subject: [PATCH 06/13] feat: add aschild --- packages/components/tabs/src/tab-content.ts | 5 +++++ packages/components/tabs/src/tab-list.ts | 5 +++++ packages/components/tabs/src/tab-trigger.ts | 5 +++++ packages/components/tabs/src/tabs.ts | 16 ++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/packages/components/tabs/src/tab-content.ts b/packages/components/tabs/src/tab-content.ts index 9b9b2768f..f2e6e81a9 100644 --- a/packages/components/tabs/src/tab-content.ts +++ b/packages/components/tabs/src/tab-content.ts @@ -26,6 +26,10 @@ const TabContent = defineComponent({ type: Boolean as PropType, default: false, }, + asChild: { + type: Boolean as PropType, + default: false, + }, }, setup(props, { slots }) { const injectedValue = inject(TABS_INJECTION_KEY) @@ -53,6 +57,7 @@ const TabContent = defineComponent({ 'data-state': dataState.value, 'data-orientation': injectedValue?.orientation, 'tabindex': '0', + 'asChild': props.asChild, }, { default: () => slots.default?.(), diff --git a/packages/components/tabs/src/tab-list.ts b/packages/components/tabs/src/tab-list.ts index 74d56d1d4..343e36911 100644 --- a/packages/components/tabs/src/tab-list.ts +++ b/packages/components/tabs/src/tab-list.ts @@ -27,6 +27,10 @@ const TabList = defineComponent({ type: Boolean as PropType, default: true, }, + asChild: { + type: Boolean as PropType, + default: false, + }, }, setup(props, { slots }) { const injectedValue = inject(TABS_INJECTION_KEY) @@ -48,6 +52,7 @@ const TabList = defineComponent({ 'tabindex': 0, 'data-orientation': injectedValue?.orientation, 'style': 'outline: none', + 'asChild': props.asChild, }, { default: () => slots.default?.(), diff --git a/packages/components/tabs/src/tab-trigger.ts b/packages/components/tabs/src/tab-trigger.ts index 3d04f1c5e..11b451ab0 100644 --- a/packages/components/tabs/src/tab-trigger.ts +++ b/packages/components/tabs/src/tab-trigger.ts @@ -30,6 +30,10 @@ const TabTrigger = defineComponent({ type: Boolean as PropType, default: false, }, + asChild: { + type: Boolean as PropType, + default: false, + }, }, setup(props, { slots }) { const injectedValue = inject(TABS_INJECTION_KEY) @@ -97,6 +101,7 @@ const TabTrigger = defineComponent({ 'data-oku-ui-tab-value': props.value, 'onClick': () => changeTab(props.value!), 'onKeydown': handleKeydown, + 'asChild': props.asChild, }, { default: () => slots.default?.(), diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts index 41dc93084..121b271bf 100644 --- a/packages/components/tabs/src/tabs.ts +++ b/packages/components/tabs/src/tabs.ts @@ -11,6 +11,10 @@ const TAB_NAME = 'TAB' as const type Orientation = 'horizontal' | 'vertical' type Direction = 'ltr' | 'rtl' +/** + * Whether a tab is activated automatically or manually. + * @defaultValue automatic + * */ type ActivationMode = 'automatic' | 'manual' interface TabsProps extends PrimitiveProps { /** @@ -50,7 +54,14 @@ interface TabsProps extends PrimitiveProps { * @see link-to-oku-docs/tab * */ orientation?: Orientation + /** + * The direction of navigation between toolbar items. + */ dir?: Direction + /** + * Whether a tab is activated automatically or manually. + * @defaultValue automatic + * */ activationMode?: ActivationMode modelValue?: string } @@ -98,6 +109,10 @@ const Tabs = defineComponent({ type: Function as PropType<(value: string) => void>, required: false, }, + asChild: { + type: Boolean as PropType, + default: false, + }, }, emits: ['update:modelValue'], setup(props, { slots, emit }) { @@ -131,6 +146,7 @@ const Tabs = defineComponent({ 'dir': props.dir, 'data-orientation': props.orientation, 'role': 'tab-group', + 'asChild': props.asChild, }, { default: () => slots.default?.(), From 24086fa79ad3a23d2bde1cf73fb4c0bedca3c8fb Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 06:59:37 +0300 Subject: [PATCH 07/13] refactor: inject and useRef --- packages/components/tabs/src/tab-content.ts | 28 ++++----- packages/components/tabs/src/tab-list.ts | 37 ++++++------ packages/components/tabs/src/tab-trigger.ts | 58 ++++++++++--------- packages/components/tabs/src/tabs.ts | 21 +++---- packages/core/use-composable/src/index.ts | 1 - .../use-composable/src/usePrimitiveElement.ts | 12 ---- 6 files changed, 76 insertions(+), 81 deletions(-) delete mode 100644 packages/core/use-composable/src/usePrimitiveElement.ts diff --git a/packages/components/tabs/src/tab-content.ts b/packages/components/tabs/src/tab-content.ts index f2e6e81a9..4ceeff918 100644 --- a/packages/components/tabs/src/tab-content.ts +++ b/packages/components/tabs/src/tab-content.ts @@ -1,13 +1,9 @@ import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' -import { type PropType, computed, defineComponent, h, inject } from 'vue' -import type { TabsProvideValue } from './tabs' -import { TABS_INJECTION_KEY } from './tabs' +import { type PropType, computed, defineComponent, h, toRefs } from 'vue' +import type { Scope } from '@oku-ui/provide' +import { useTabsInject } from './tabs' -/* ------------------------------------------------------------------------------------------------- - * TabTrigger - * ----------------------------------------------------------------------------------------------- */ - -const TAB_CONTENT_NAME = 'TabContent' as const +const TAB_CONTENT_NAME = 'OkuTabContent' as const interface TabsContentProps extends PrimitiveProps { value?: string @@ -30,19 +26,25 @@ const TabContent = defineComponent({ type: Boolean as PropType, default: false, }, + scopeTabs: { + type: Object as unknown as PropType, + required: false, + default: undefined, + }, }, setup(props, { slots }) { - const injectedValue = inject(TABS_INJECTION_KEY) + const { scopeTabs } = toRefs(props) + const injectTabs = useTabsInject(TAB_CONTENT_NAME, scopeTabs.value) const dataState = computed<'active' | 'inactive'>(() => { - return injectedValue?.modelValue?.value === props.value + return injectTabs.value.modelValue?.value === props.value ? 'active' : 'inactive' }) const shouldRender = computed(() => { return ( - injectedValue?.modelValue?.value === props.value || props.forceMount + injectTabs.value.modelValue?.value === props.value || props.forceMount ) }) @@ -52,10 +54,10 @@ const TabContent = defineComponent({ ? h( Primitive.div, { - 'vIf': injectedValue?.modelValue?.value === props.value, + 'vIf': injectTabs.value.modelValue?.value === props.value, 'role': 'tab-content', 'data-state': dataState.value, - 'data-orientation': injectedValue?.orientation, + 'data-orientation': injectTabs.value.orientation, 'tabindex': '0', 'asChild': props.asChild, }, diff --git a/packages/components/tabs/src/tab-list.ts b/packages/components/tabs/src/tab-list.ts index 343e36911..7128c6070 100644 --- a/packages/components/tabs/src/tab-list.ts +++ b/packages/components/tabs/src/tab-list.ts @@ -4,16 +4,12 @@ import { type PrimitiveProps, } from '@oku-ui/primitive' import type { PropType } from 'vue' -import { defineComponent, h, inject, onMounted } from 'vue' -import { usePrimitiveElement } from '@oku-ui/use-composable' -import type { TabsProvideValue } from './tabs' -import { TABS_INJECTION_KEY } from './tabs' +import { defineComponent, h, onMounted, toRefs } from 'vue' +import { useRef } from '@oku-ui/use-composable' +import type { Scope } from '@oku-ui/provide' +import { useTabsInject } from './tabs' -/* ------------------------------------------------------------------------------------------------- - * TabList - * ----------------------------------------------------------------------------------------------- */ - -const TAB_LIST_NAME = 'TabList' as const +const TAB_LIST_NAME = 'OkuTabList' as const interface TabListProps extends PrimitiveProps { loop?: boolean @@ -31,15 +27,22 @@ const TabList = defineComponent({ type: Boolean as PropType, default: false, }, + scopeTabs: { + type: Object as unknown as PropType, + required: false, + default: undefined, + }, }, setup(props, { slots }) { - const injectedValue = inject(TABS_INJECTION_KEY) - const { primitiveElement, currentElement: parentElement } - = usePrimitiveElement() + const { scopeTabs } = toRefs(props) + const injectTabs = useTabsInject(TAB_LIST_NAME, scopeTabs.value) + + const { $el, newRef: parentElement } + = useRef() onMounted(() => { - injectedValue!.parentElement.value = parentElement.value - injectedValue!.loop = props.loop + injectTabs.value.parentElement.value = $el.value + injectTabs.value.loop = props.loop }) return () => @@ -47,10 +50,10 @@ const TabList = defineComponent({ Primitive.div, { 'role': 'tab-list', - 'ref': primitiveElement, - 'aria-orientation': injectedValue?.orientation, + 'ref': parentElement, + 'aria-orientation': injectTabs.value.orientation, 'tabindex': 0, - 'data-orientation': injectedValue?.orientation, + 'data-orientation': injectTabs.value.orientation, 'style': 'outline: none', 'asChild': props.asChild, }, diff --git a/packages/components/tabs/src/tab-trigger.ts b/packages/components/tabs/src/tab-trigger.ts index 11b451ab0..05696254d 100644 --- a/packages/components/tabs/src/tab-trigger.ts +++ b/packages/components/tabs/src/tab-trigger.ts @@ -1,17 +1,12 @@ import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' -import { type PropType, computed, defineComponent, h, inject } from 'vue' +import { type PropType, computed, defineComponent, h, toRefs } from 'vue' import { - useArrowNavigation, - usePrimitiveElement, + useArrowNavigation, useRef, } from '@oku-ui/use-composable' -import type { TabsProvideValue } from './tabs' -import { TABS_INJECTION_KEY } from './tabs' +import type { Scope } from '@oku-ui/provide' +import { useTabsInject } from './tabs' -/* ------------------------------------------------------------------------------------------------- - * TabTrigger - * ----------------------------------------------------------------------------------------------- */ - -const TAB_TRIGGER_NAME = 'TabTrigger' as const +const TAB_TRIGGER_NAME = 'OkuTabTrigger' as const interface TabsTriggerProps extends PrimitiveProps { value: string @@ -34,33 +29,40 @@ const TabTrigger = defineComponent({ type: Boolean as PropType, default: false, }, + scopeTabs: { + type: Object as unknown as PropType, + required: false, + default: undefined, + }, }, setup(props, { slots }) { - const injectedValue = inject(TABS_INJECTION_KEY) - const { primitiveElement, currentElement } = usePrimitiveElement() + const { scopeTabs } = toRefs(props) + const injectedValue = useTabsInject(TAB_TRIGGER_NAME, scopeTabs.value) + + const { $el, newRef: currentElement } = useRef() function changeTab(value: string) { - injectedValue?.changeModelValue(value) + injectedValue.value.changeModelValue(value) } function handleKeydown(e: KeyboardEvent) { - if (!injectedValue?.parentElement.value || !currentElement.value) + if (!injectedValue.value.parentElement.value || $el.value) return const newSelectedElement = useArrowNavigation( e, - currentElement.value, - injectedValue?.parentElement.value, + $el.value, + injectedValue.value.parentElement.value, { - arrowKeyOptions: injectedValue?.orientation, - loop: injectedValue?.loop, + arrowKeyOptions: injectedValue.value.orientation, + loop: injectedValue.value.loop, }, ) if (newSelectedElement) { newSelectedElement.focus() - injectedValue!.currentFocusedElement!.value = newSelectedElement + injectedValue.value.currentFocusedElement!.value = newSelectedElement - if (injectedValue?.activationMode === 'automatic') { + if (injectedValue.value.activationMode === 'automatic') { changeTab( newSelectedElement.getAttribute('data-oku-ui-tab-value')!, ) @@ -69,12 +71,12 @@ const TabTrigger = defineComponent({ } const getTabIndex = computed(() => { - if (!injectedValue?.currentFocusedElement?.value) { - return injectedValue?.modelValue?.value === props.value ? '0' : '-1' + if (!injectedValue.value.currentFocusedElement?.value) { + return injectedValue.value.modelValue?.value === props.value ? '0' : '-1' } else { - return injectedValue?.currentFocusedElement?.value - === currentElement.value + return injectedValue.value.currentFocusedElement?.value + === $el.value ? '0' : '-1' } @@ -84,19 +86,19 @@ const TabTrigger = defineComponent({ h( Primitive.button, { - 'ref': primitiveElement, + 'ref': currentElement, 'type': Primitive.button, 'role': 'tab', 'aria-selected': - injectedValue?.modelValue?.value === props.value ? 'true' : 'false', + injectedValue.value.modelValue?.value === props.value ? 'true' : 'false', 'data-state': - injectedValue?.modelValue?.value === props.value + injectedValue.value.modelValue?.value === props.value ? 'active' : 'inactive', 'disabled': props.disabled, 'data-disabled': props.disabled ? '' : undefined, 'tabindex': getTabIndex.value, - 'data-orientation': injectedValue?.orientation, + 'data-orientation': injectedValue.value.orientation, 'data-oku-ui-collection-item': true, 'data-oku-ui-tab-value': props.value, 'onClick': () => changeTab(props.value!), diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts index 121b271bf..0d6f7f83d 100644 --- a/packages/components/tabs/src/tabs.ts +++ b/packages/components/tabs/src/tabs.ts @@ -1,13 +1,10 @@ import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' -import { defineComponent, h, provide, ref } from 'vue' -import type { InjectionKey, PropType, Ref } from 'vue' +import { defineComponent, h, ref } from 'vue' +import type { PropType, Ref } from 'vue' import { useVModel } from '@vueuse/core' +import { createProvideScope } from '@oku-ui/provide' -/* ------------------------------------------------------------------------------------------------- - * Tabs - * ----------------------------------------------------------------------------------------------- */ - -const TAB_NAME = 'TAB' as const +const TAB_NAME = 'OkuTab' as const type Orientation = 'horizontal' | 'vertical' type Direction = 'ltr' | 'rtl' @@ -77,7 +74,10 @@ interface TabsProvideValue { loop: boolean } -const TABS_INJECTION_KEY = Symbol(`${TAB_NAME} provide key`) as InjectionKey +export const [createTabsProvider, _createTabsScope] = createProvideScope(TAB_NAME) + +export const [TabsProvider, useTabsInject] + = createTabsProvider(TAB_NAME) const Tabs = defineComponent({ name: TAB_NAME, @@ -124,7 +124,7 @@ const Tabs = defineComponent({ passive: true, }) - provide(TABS_INJECTION_KEY, { + TabsProvider({ modelValue, changeModelValue: (value: string) => { modelValue.value = value @@ -137,6 +137,7 @@ const Tabs = defineComponent({ dir: props.dir, loop: true, activationMode: props.activationMode, + scope: undefined, }) return () => @@ -159,6 +160,6 @@ type _TabsProps = MergeProps const OkuTabs = Tabs as typeof Tabs & (new () => { $props: _TabsProps }) -export { OkuTabs, TABS_INJECTION_KEY, TabsProvideValue } +export { OkuTabs, TabsProvideValue } export type { TabsProps } diff --git a/packages/core/use-composable/src/index.ts b/packages/core/use-composable/src/index.ts index 2c7d34f8b..bbcafe8a6 100644 --- a/packages/core/use-composable/src/index.ts +++ b/packages/core/use-composable/src/index.ts @@ -8,6 +8,5 @@ export { useRef } from './useRef' export { unrefElement } from './unrefElement' export { useId } from './useId' export type { MaybeComputedElementRef } from './unrefElement' -export { usePrimitiveElement } from './usePrimitiveElement' export { useArrowNavigation } from './useArrowNavigation' export { computedEager, syncRef } diff --git a/packages/core/use-composable/src/usePrimitiveElement.ts b/packages/core/use-composable/src/usePrimitiveElement.ts deleted file mode 100644 index d9601c7c8..000000000 --- a/packages/core/use-composable/src/usePrimitiveElement.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { computed, ref } from 'vue' -import { unrefElement } from './unrefElement' - -export function usePrimitiveElement() { - const primitiveElement = ref() - const currentElement = computed(() => unrefElement(primitiveElement)) - - return { - primitiveElement, - currentElement, - } -} From 01ee3f45b5bce038fab4a68946525ea15ab20076 Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 07:10:34 +0300 Subject: [PATCH 08/13] fix: type --- packages/components/tabs/src/index.ts | 2 +- packages/components/tabs/src/tabs.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/components/tabs/src/index.ts b/packages/components/tabs/src/index.ts index e28afb251..517b59858 100644 --- a/packages/components/tabs/src/index.ts +++ b/packages/components/tabs/src/index.ts @@ -3,7 +3,7 @@ export { OkuTabList } from './tab-list' export { OkuTabTrigger } from './tab-trigger' export { OkuTabContent } from './tab-content' -export type { TabsProps, TabsProvideValue } from './tabs' +export type { TabsProps } from './tabs' export { type TabListProps } from './tab-list' export { type TabsTriggerProps } from './tab-trigger' export { type TabsContentProps } from './tab-content' diff --git a/packages/components/tabs/src/tabs.ts b/packages/components/tabs/src/tabs.ts index 0d6f7f83d..cbbe47d77 100644 --- a/packages/components/tabs/src/tabs.ts +++ b/packages/components/tabs/src/tabs.ts @@ -1,4 +1,5 @@ -import { type MergeProps, Primitive, type PrimitiveProps } from '@oku-ui/primitive' +import type { MergeProps, PrimitiveProps, RefElement } from '@oku-ui/primitive' +import { Primitive } from '@oku-ui/primitive' import { defineComponent, h, ref } from 'vue' import type { PropType, Ref } from 'vue' import { useVModel } from '@vueuse/core' @@ -158,8 +159,10 @@ const Tabs = defineComponent({ type _TabsProps = MergeProps +type TabsRef = RefElement + const OkuTabs = Tabs as typeof Tabs & (new () => { $props: _TabsProps }) -export { OkuTabs, TabsProvideValue } +export { OkuTabs } -export type { TabsProps } +export type { TabsProps, TabsRef } From 61e953e74b7a3d4ad3573efecbb819ebab68f388 Mon Sep 17 00:00:00 2001 From: productdevbook Date: Thu, 20 Jul 2023 08:12:14 +0300 Subject: [PATCH 09/13] chore: delete @vueuse/core root --- package.json | 3 --- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9a63e35e3..981bc9e3e 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,6 @@ "clean:dts": "rimraf 'playground/vue3/src/components.d.ts' 'playground/vue3/src/auto-imports.d.ts' 'playground/nuxt3/.nuxt'", "update:version": "esno scripts/update-version.ts" }, - "dependencies": { - "@vueuse/core": "^10.2.1" - }, "devDependencies": { "@egoist/tailwindcss-icons": "^1.1.0", "@iconify-json/ph": "^1.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a02cf353..847b64b8b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,10 +12,6 @@ overrides: importers: .: - dependencies: - '@vueuse/core': - specifier: ^10.2.1 - version: 10.2.1(vue@3.3.4) devDependencies: '@egoist/tailwindcss-icons': specifier: ^1.1.0 @@ -576,7 +572,7 @@ importers: version: 5.1.6 unplugin-auto-import: specifier: ^0.16.6 - version: 0.16.6(@vueuse/core@10.2.1)(rollup@3.21.0) + version: 0.16.6(rollup@3.21.0) unplugin-vue-components: specifier: ^0.25.1 version: 0.25.1(rollup@3.21.0)(vue@3.3.4) @@ -4852,6 +4848,7 @@ packages: /@types/web-bluetooth@0.0.17: resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} + dev: false /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} @@ -5428,9 +5425,11 @@ packages: transitivePeerDependencies: - '@vue/composition-api' - vue + dev: false /@vueuse/metadata@10.2.1: resolution: {integrity: sha512-3Gt68mY/i6bQvFqx7cuGBzrCCQu17OBaGWS5JdwISpMsHnMKKjC2FeB5OAfMcCQ0oINfADP3i9A4PPRo0peHdQ==} + dev: false /@vueuse/shared@10.2.1(vue@3.3.4): resolution: {integrity: sha512-QWHq2bSuGptkcxx4f4M/fBYC3Y8d3M2UYyLsyzoPgEoVzJURQ0oJeWXu79OiLlBb8gTKkqe4mO85T/sf39mmiw==} @@ -5439,6 +5438,7 @@ packages: transitivePeerDependencies: - '@vue/composition-api' - vue + dev: false /@webassemblyjs/ast@1.11.5: resolution: {integrity: sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==} @@ -13481,7 +13481,7 @@ packages: engines: {node: '>= 0.8'} dev: true - /unplugin-auto-import@0.16.6(@vueuse/core@10.2.1)(rollup@3.21.0): + /unplugin-auto-import@0.16.6(rollup@3.21.0): resolution: {integrity: sha512-M+YIITkx3C/Hg38hp8HmswP5mShUUyJOzpifv7RTlAbeFlO2Tyw0pwrogSSxnipHDPTtI8VHFBpkYkNKzYSuyA==} engines: {node: '>=14'} peerDependencies: @@ -13495,7 +13495,6 @@ packages: dependencies: '@antfu/utils': 0.7.5 '@rollup/pluginutils': 5.0.2(rollup@3.21.0) - '@vueuse/core': 10.2.1(vue@3.3.4) fast-glob: 3.3.0 local-pkg: 0.4.3 magic-string: 0.30.1 @@ -14128,6 +14127,7 @@ packages: optional: true dependencies: vue: 3.3.4 + dev: false /vue-devtools-stub@0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} From 781ea4ed744f367f41c8f6c686e7778b1c2018a5 Mon Sep 17 00:00:00 2001 From: productdevbook Date: Wed, 9 Aug 2023 12:59:08 +0300 Subject: [PATCH 10/13] fix: lint --- package.json | 2 +- playground/vue3/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 30fea2b01..62bb1719e 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,9 @@ "@oku-ui/provide": "workspace:^", "@oku-ui/roving-focus": "workspace:^", "@oku-ui/separator": "workspace:^", - "@oku-ui/tabs": "workspace:^", "@oku-ui/slot": "workspace:^", "@oku-ui/switch": "workspace:^", + "@oku-ui/tabs": "workspace:^", "@oku-ui/toggle": "workspace:^", "@oku-ui/use-composable": "workspace:^", "@oku-ui/utils": "workspace:^", diff --git a/playground/vue3/package.json b/playground/vue3/package.json index 552848ee6..f4c489fb2 100644 --- a/playground/vue3/package.json +++ b/playground/vue3/package.json @@ -18,9 +18,9 @@ "@oku-ui/progress": "workspace:^", "@oku-ui/roving-focus": "workspace:^", "@oku-ui/separator": "workspace:^", - "@oku-ui/tabs": "workspace:^", "@oku-ui/slot": "workspace:^", "@oku-ui/switch": "workspace:^", + "@oku-ui/tabs": "workspace:^", "vite-plugin-pages": "^0.31.0", "vue": "^3.3.4", "vue-router": "^4.2.4" From 257ea919879ba1dc38e6ff558e62ca7540139e62 Mon Sep 17 00:00:00 2001 From: productdevbook Date: Sun, 13 Aug 2023 16:39:36 +0300 Subject: [PATCH 11/13] refactor: struct and 1:1 radix --- packages/components/tabs/package.json | 3 + .../components/tabs/src/stories/TabsDemo.vue | 3 +- packages/components/tabs/src/tab-content.ts | 109 ++++++------ packages/components/tabs/src/tab-list.ts | 91 +++++----- packages/components/tabs/src/tab-trigger.ts | 165 +++++++++--------- packages/components/tabs/src/tabs.ts | 112 +++++++----- packages/components/tabs/src/utils.ts | 7 + packages/core/use-composable/src/index.ts | 1 - .../use-composable/src/useArrowNavigation.ts | 130 -------------- pnpm-lock.yaml | 9 + 10 files changed, 277 insertions(+), 353 deletions(-) create mode 100644 packages/components/tabs/src/utils.ts delete mode 100644 packages/core/use-composable/src/useArrowNavigation.ts diff --git a/packages/components/tabs/package.json b/packages/components/tabs/package.json index a344c1d38..561893bcf 100644 --- a/packages/components/tabs/package.json +++ b/packages/components/tabs/package.json @@ -33,8 +33,11 @@ "vue": "^3.3.4" }, "dependencies": { + "@oku-ui/direction": "latest", + "@oku-ui/presence": "latest", "@oku-ui/primitive": "latest", "@oku-ui/provide": "latest", + "@oku-ui/roving-focus": "latest", "@oku-ui/use-composable": "latest", "@oku-ui/utils": "latest" }, diff --git a/packages/components/tabs/src/stories/TabsDemo.vue b/packages/components/tabs/src/stories/TabsDemo.vue index ac3fe5aae..ba5fc3e26 100644 --- a/packages/components/tabs/src/stories/TabsDemo.vue +++ b/packages/components/tabs/src/stories/TabsDemo.vue @@ -9,11 +9,10 @@ import {