From db4d588f240eeb07543a82f5d1906a2b8556a139 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Mon, 15 Apr 2024 16:56:00 +0800 Subject: [PATCH 01/39] wip: init KMenu component --- components/Menu/__test__/menu.spec.ts | 32 ++++++++++++++++++ components/Menu/package.json | 47 +++++++++++++++++++++++++++ components/Menu/src/index.svelte | 19 +++++++++++ components/Menu/src/index.ts | 5 +++ components/Menu/src/types.d.ts | 6 ++++ components/Menu/tsconfig.json | 11 +++++++ components/index.ts | 1 + package.json | 5 +-- pnpm-lock.yaml | 45 +++++++++++++++++++++---- preset/src/shortcuts/index.ts | 6 ++++ preset/src/shortcuts/src/menu.ts | 3 ++ 11 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 components/Menu/__test__/menu.spec.ts create mode 100644 components/Menu/package.json create mode 100644 components/Menu/src/index.svelte create mode 100644 components/Menu/src/index.ts create mode 100644 components/Menu/src/types.d.ts create mode 100644 components/Menu/tsconfig.json create mode 100644 preset/src/shortcuts/src/menu.ts diff --git a/components/Menu/__test__/menu.spec.ts b/components/Menu/__test__/menu.spec.ts new file mode 100644 index 00000000..52352fac --- /dev/null +++ b/components/Menu/__test__/menu.spec.ts @@ -0,0 +1,32 @@ +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import KMenu from '../src'; + +let host; + +const initHost = () => { + host = globalThis.document.createElement('div'); + host.setAttribute('id', 'host'); + globalThis.document.body.appendChild(host); +}; +beforeEach(() => { + initHost(); + vi.useFakeTimers(); +}); +afterEach(() => { + host.remove(); + vi.useRealTimers(); +}); + +describe('Test: KMenu', () => { + test('props: cls', async () => { + const instance = new KMenu({ + target: host, + props: { + cls: 'k-menu--test' + } + }); + expect(instance).toBeTruthy(); + expect(host!.innerHTML.includes('k-menu--test')).toBeTruthy(); + expect(host.innerHTML).matchSnapshot(); + }); +}); diff --git a/components/Menu/package.json b/components/Menu/package.json new file mode 100644 index 00000000..34c658ac --- /dev/null +++ b/components/Menu/package.json @@ -0,0 +1,47 @@ +{ + "name": "@ikun-ui/menu", + "version": "0.2.6", + "type": "module", + "main": "src/index.ts", + "types": "src/index.d.ts", + "svelte": "src/index.ts", + "keywords": [ + "svelte", + "svelte3", + "web component", + "component", + "react", + "vue", + "svelte-kit", + "dx" + ], + "files": [ + "dist", + "package.json" + ], + "scripts": { + "build": "svelte-package -i src", + "publish:pre": "node ../../scripts/pre-publish.js", + "publish:npm": "pnpm run publish:pre && pnpm publish --no-git-checks --access public" + }, + "publishConfig": { + "access": "public", + "main": "dist/index.js", + "module": "dist/index.js", + "svelte": "dist/index.js", + "types": "dist/index.d.ts" + }, + "dependencies": { + "@ikun-ui/icon": "workspace:*", + "@ikun-ui/utils": "workspace:*", + "baiwusanyu-utils": "^1.0.18", + "clsx": "^2.0.0", + "svelte": "^4.2.7" + }, + "devDependencies": { + "@sveltejs/package": "^2.3.1", + "@tsconfig/svelte": "^5.0.4", + "tslib": "^2.6.2", + "typescript": "^5.4.4" + } +} diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte new file mode 100644 index 00000000..8a0701f3 --- /dev/null +++ b/components/Menu/src/index.svelte @@ -0,0 +1,19 @@ + + +
diff --git a/components/Menu/src/index.ts b/components/Menu/src/index.ts new file mode 100644 index 00000000..ef6362b4 --- /dev/null +++ b/components/Menu/src/index.ts @@ -0,0 +1,5 @@ +/// +import Menu from './index.svelte'; +export { Menu as KMenu }; + +export default Menu; diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts new file mode 100644 index 00000000..86f469e0 --- /dev/null +++ b/components/Menu/src/types.d.ts @@ -0,0 +1,6 @@ +/// +import type { ClassValue } from 'clsx'; +export type KMenuProps = { + cls: ClassValue; + attrs: Record; +}; diff --git a/components/Menu/tsconfig.json b/components/Menu/tsconfig.json new file mode 100644 index 00000000..fe0d7c4f --- /dev/null +++ b/components/Menu/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + + "compilerOptions": { + "noImplicitAny": true, + "strict": true, + "declaration": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.svelte"], + "exclude": ["node_modules/*", "**/*.spec.ts"] +} diff --git a/components/index.ts b/components/index.ts index 7763c2f5..d0cb94e2 100644 --- a/components/index.ts +++ b/components/index.ts @@ -68,3 +68,4 @@ export * from '@ikun-ui/timeline'; export * from '@ikun-ui/calendar'; export * from '@ikun-ui/indicators'; export * from '@ikun-ui/tour'; +export * from '@ikun-ui/menu'; diff --git a/package.json b/package.json index bc500cbf..490e40e1 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "clean:deps": "node scripts/clean-deps.js && node scripts/clean-root-deps.js", "prepare": "npx simple-git-hooks", "update:deps": "npx taze -w -r major && pnpm run init", - "create:new:comp": "node scripts/new-component.js tour" + "create:new:comp": "node scripts/new-component.js menu" }, "peerDependencies": { "baiwusanyu-utils": "^1.0.18", @@ -151,7 +151,8 @@ "baiwusanyu-utils": "^1.0.18", "clsx": "^2.1.0", "dayjs": "^1.11.10", - "@ikun-ui/indicators": "workspace:*" + "@ikun-ui/indicators": "workspace:*", + "@ikun-ui/menu": "workspace:*" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96018301..58481b75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,6 +134,9 @@ importers: '@ikun-ui/mask': specifier: workspace:* version: link:components/Mask + '@ikun-ui/menu': + specifier: workspace:* + version: link:components/Menu '@ikun-ui/message': specifier: workspace:* version: link:components/Message @@ -1759,6 +1762,37 @@ importers: specifier: ^5.4.4 version: 5.4.4 + components/Menu: + dependencies: + '@ikun-ui/icon': + specifier: workspace:* + version: link:../Icon + '@ikun-ui/utils': + specifier: workspace:* + version: link:../../utils + baiwusanyu-utils: + specifier: ^1.0.18 + version: 1.0.18(ansi-colors@4.1.3)(moment@2.29.4) + clsx: + specifier: ^2.0.0 + version: 2.1.0 + svelte: + specifier: ^4.2.7 + version: 4.2.12 + devDependencies: + '@sveltejs/package': + specifier: ^2.3.1 + version: 2.3.1(svelte@4.2.12)(typescript@5.4.4) + '@tsconfig/svelte': + specifier: ^5.0.4 + version: 5.0.4 + tslib: + specifier: ^2.6.2 + version: 2.6.2 + typescript: + specifier: ^5.4.4 + version: 5.4.4 + components/Message: dependencies: '@ikun-ui/notify': @@ -4661,7 +4695,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 + semver: 7.6.0 ts-api-utils: 1.0.3(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: @@ -4703,7 +4737,7 @@ packages: '@typescript-eslint/types': 7.3.1 '@typescript-eslint/typescript-estree': 7.3.1(typescript@5.4.3) eslint: 8.57.0 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - supports-color - typescript @@ -7372,7 +7406,7 @@ packages: dev: true /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, tarball: https://r2.cnpmjs.org/lru-cache/-/lru-cache-5.1.1.tgz} + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 dev: true @@ -7413,7 +7447,6 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - dev: true /mark.js@8.11.1: resolution: {integrity: sha1-GA8fnr74sOY45BZq1S24eb6y/8U=} @@ -7964,7 +7997,7 @@ packages: /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: - '@types/estree': 1.0.3 + '@types/estree': 1.0.5 estree-walker: 3.0.3 is-reference: 3.0.2 @@ -8992,7 +9025,7 @@ packages: estree-walker: 3.0.3 is-reference: 3.0.2 locate-character: 3.0.0 - magic-string: 0.30.8 + magic-string: 0.30.9 periscopic: 3.1.0 /symbol-tree@3.2.4: diff --git a/preset/src/shortcuts/index.ts b/preset/src/shortcuts/index.ts index b6abdff1..02fc7ac4 100644 --- a/preset/src/shortcuts/index.ts +++ b/preset/src/shortcuts/index.ts @@ -1,3 +1,4 @@ +import { menuShortcuts } from './src/menu'; import { indicatorsShortcuts } from './src/indicators'; import { tourShortcuts } from './src/tour'; import { calendarShortcuts } from './src/calendar'; @@ -71,6 +72,8 @@ export const defaultShortcuts = [ commonShortcuts, // don't remove // anchor defaultShortcuts + // menu + menuShortcuts, // indicators indicatorsShortcuts, // tour @@ -196,6 +199,7 @@ export const defaultShortcuts = [ export function getSafeList() { // don't remove // anchor shortcuts + const menuList = Object.keys(menuShortcuts); const indicatorsList = Object.keys(indicatorsShortcuts); const tourList = Object.keys(tourShortcuts); const calendarList = Object.keys(calendarShortcuts); @@ -261,6 +265,7 @@ export function getSafeList() { let res = iconList // don't remove // anchor list + .concat(menuList) .concat(indicatorsList) .concat(tourList) .concat(calendarList) @@ -400,3 +405,4 @@ export { timelineShortcuts } from './src/timeline'; export { calendarShortcuts } from './src/calendar'; export { indicatorsShortcuts } from './src/indicators'; export { tourShortcuts } from './src/tour'; +export { menuShortcuts } from './src/menu'; diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts new file mode 100644 index 00000000..624f842e --- /dev/null +++ b/preset/src/shortcuts/src/menu.ts @@ -0,0 +1,3 @@ +export const menuShortcuts: Record = { + 'k-menu': '' +}; From 2e6cf3d8df4b1c2813cf8f7979048b1a4bd336f2 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Mon, 15 Apr 2024 18:14:10 +0800 Subject: [PATCH 02/39] wip: KMEnu api design --- components/Menu/src/types.d.ts | 155 +++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 86f469e0..f3f089af 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -1,6 +1,161 @@ /// import type { ClassValue } from 'clsx'; export type KMenuProps = { + /** + * TODO: 展开图标 + */ + expandIcon?: string + /** + * TODO: inline 模式的菜单缩进宽度 + * @default 24 + */ + inlineIndent?: number + /** + * TODO: inline 时菜单是否收起状态 (指显示图标的mini模式和展开到常规模式) + * @default 24 + */ + inlineCollapsed?: number + /** + * TODO: 菜单内容 + */ + items?: KItemType[] + /** + * TODO: 菜单类型,现在支持垂直、水平、和内嵌模式三种 + * `vertical` 和 `inline` 的区别在于 `vertical` 子菜单以 popover 形式出现 + * @default `vertical` + */ + mode?: `vertical` | `horizontal` | `inline` + /** + * TODO: 当前展开的 SubMenu 菜单项 key 数组 + * @default `[]` + */ + openUids?: string[] + /** + * TODO: 用于自定义 Menu 水平空间不足时的省略收缩的图标 + */ + overflowedIndicator?: string + /** + * TODO: 当前选中的菜单项 key 数组 + * @default `[]` + */ + selectedUids?: string[] + /** + * TODO: 是否允许选中(为 false, 仅不触发 select事件) + * @default false + */ + selectable?: boolean + /** + * TODO: 用户鼠标离开子菜单后关闭延时,单位:毫秒 + * @default 100ms + */ + subMenuCloseDelay?: boolean + /** + * TODO: 用户鼠标进入子菜单后开启延时,单位:毫秒 + * @default 0 + */ + subMenuOpenDelay?: number + /** + * TODO: 主题 + * @default 'light' + */ + theme?: 'light' | 'dark' + /** + * TODO: SubMenu 展开/关闭的触发行为(非 inline 模式) + * @default 'hover' + */ + triggerSubMenuAction?: 'hover' | 'click' cls: ClassValue; attrs: Record; }; + +// TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) +// TODO: onOpenChange SubMenu 展开/关闭的回调 +// TODO: onSelect 被选中时调用(点击子菜单标题不触发) + +// TODO: slots overflowedIndicator 用于自定义 Menu 水平空间不足时的省略收缩的图标 +// TODO: slots expandIcon 展开图标 + +export type KItemType = KMenuItemType | DividerItem | SubMenuType | GroupItem + +export type KMenuItemType = { + /** + * TODO: 菜单图标 + */ + icon?: string + /** + * TODO: 菜单项标题 + */ + label?: string + /** + * TODO: item 的唯一标志 + */ + uid?: string + /** + * TODO: 设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) + */ + title?: string + /** + * TODO: 是否禁用 + * @default false + */ + disabled: boolean + /** + * TODO: 展示错误状态样式 + * @default false + */ + danger: boolean +} + +export type SubMenuType = { + /** + * TODO: 菜单图标 + */ + icon?: string + /** + * TODO: 菜单项标题 + */ + label?: string + /** + * TODO: item 的唯一标志 + */ + uid?: string + /** + * TODO: 是否禁用 + * @default false + */ + disabled: boolean + /** + * TODO: 设置子菜单的主题,默认从 Menu 上继承 + * @default 'light' + */ + theme?: 'light' | 'dark' + /** + * TODO: 子菜单的菜单项 + */ + children?: KItemType[] + /** + * TODO: 子菜单样式,mode="inline" 时无效 + */ + popupClassName?: string +}; + +// TODO: onTitleClick 点击子菜单标题 + +export type GroupItem = { + type?: 'group', // Must have + /** + * TODO: 分组标题 + */ + label: string + /** + * TODO: 分组的菜单项 + */ + children: KMenuItemType[], +}; + +export type DividerItem = { + type?: 'divider', // Must have +}; + +// TODO: Items Slots slots label 分组标题 +// TODO: Items Slots slots icon 菜单图标 From 747e77604c2d68ed4db82beff6caf58fc1015bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:39:58 +0800 Subject: [PATCH 03/39] wip: temp commit --- components/Menu/src/index.svelte | 21 ++++++++++++++----- components/Menu/src/index.ts | 8 ++++++++ components/Menu/src/types.d.ts | 35 ++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 8a0701f3..02a266c0 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -2,18 +2,29 @@ import { getPrefixCls } from '@ikun-ui/utils'; import { clsx } from 'clsx'; import type { KMenuProps } from './types'; - + export let triggerSubMenuAction: KMenuProps['triggerSubMenuAction'] = 'hover'; + export let subMenuCloseDelay: KMenuProps['subMenuCloseDelay'] = 100; + export let subMenuOpenDelay: KMenuProps['subMenuOpenDelay'] = 0; + export let items: KMenuProps['items'] = []; + export let expandIcon: KMenuProps['expandIcon'] = 'i-carbon-chevron-down'; + export let overflowedIndicator: KMenuProps['overflowedIndicator'] = 'i-carbon-overflow-menu-horizontal'; + export let mode: KMenuProps['mode'] = 'vertical'; export let cls: KMenuProps['cls'] = undefined; export let attrs: KMenuProps['attrs'] = {}; const prefixCls = getPrefixCls('menu'); $: cnames = clsx( prefixCls, - { - [`${prefixCls}--base`]: true - }, cls ); -
+
+ {#if mode !== 'horizontal'} + {#each items as item, index (item.uid)} +
+ {item.uid} +
+ {/each} + {/if} +
diff --git a/components/Menu/src/index.ts b/components/Menu/src/index.ts index ef6362b4..a0df1de6 100644 --- a/components/Menu/src/index.ts +++ b/components/Menu/src/index.ts @@ -3,3 +3,11 @@ import Menu from './index.svelte'; export { Menu as KMenu }; export default Menu; + +export type { + KMenuProps, + DividerItem, + GroupItem, + SubMenuType, + KMenuItemType +} from './types' diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index f3f089af..670f947c 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -2,7 +2,8 @@ import type { ClassValue } from 'clsx'; export type KMenuProps = { /** - * TODO: 展开图标 + * TODO: 🎯 展开图标 + * @default 'i-carbon-chevron-down' */ expandIcon?: string /** @@ -16,11 +17,11 @@ export type KMenuProps = { */ inlineCollapsed?: number /** - * TODO: 菜单内容 + * TODO: 🎯 菜单内容 */ - items?: KItemType[] + items: KItemType[] /** - * TODO: 菜单类型,现在支持垂直、水平、和内嵌模式三种 + * TODO: 🎯 菜单类型,现在支持垂直、水平、和内嵌模式三种 * `vertical` 和 `inline` 的区别在于 `vertical` 子菜单以 popover 形式出现 * @default `vertical` */ @@ -31,7 +32,7 @@ export type KMenuProps = { */ openUids?: string[] /** - * TODO: 用于自定义 Menu 水平空间不足时的省略收缩的图标 + * TODO: 🎯 用于自定义 Menu 水平空间不足时的省略收缩的图标 */ overflowedIndicator?: string /** @@ -45,12 +46,12 @@ export type KMenuProps = { */ selectable?: boolean /** - * TODO: 用户鼠标离开子菜单后关闭延时,单位:毫秒 + * TODO: 🎯 用户鼠标离开子菜单后关闭延时,单位:毫秒 * @default 100ms */ subMenuCloseDelay?: boolean /** - * TODO: 用户鼠标进入子菜单后开启延时,单位:毫秒 + * TODO: 🎯 用户鼠标进入子菜单后开启延时,单位:毫秒 * @default 0 */ subMenuOpenDelay?: number @@ -60,7 +61,7 @@ export type KMenuProps = { */ theme?: 'light' | 'dark' /** - * TODO: SubMenu 展开/关闭的触发行为(非 inline 模式) + * TODO: 🎯 SubMenu 展开/关闭的触发行为(非 inline 模式) * @default 'hover' */ triggerSubMenuAction?: 'hover' | 'click' @@ -98,12 +99,12 @@ export type KMenuItemType = { * TODO: 是否禁用 * @default false */ - disabled: boolean + disabled?: boolean /** * TODO: 展示错误状态样式 * @default false */ - danger: boolean + danger?: boolean } export type SubMenuType = { @@ -123,7 +124,7 @@ export type SubMenuType = { * TODO: 是否禁用 * @default false */ - disabled: boolean + disabled?: boolean /** * TODO: 设置子菜单的主题,默认从 Menu 上继承 * @default 'light' @@ -146,15 +147,23 @@ export type GroupItem = { /** * TODO: 分组标题 */ - label: string + label?: string + /** + * TODO: item 的唯一标志 + */ + uid?: string /** * TODO: 分组的菜单项 */ - children: KMenuItemType[], + children?: KItemType[], }; export type DividerItem = { type?: 'divider', // Must have + /** + * TODO: item 的唯一标志 + */ + uid?: string }; // TODO: Items Slots slots label 分组标题 From c7b1f034ba2bbd91b547b91198e02bc2c2b0158c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:39:42 +0800 Subject: [PATCH 04/39] wip: temp commit --- components/Menu/src/index.svelte | 12 +++---- components/Menu/src/index.ts | 3 +- components/Menu/src/item.svelte | 15 +++++++++ components/Menu/src/types.d.ts | 55 +++----------------------------- 4 files changed, 27 insertions(+), 58 deletions(-) create mode 100644 components/Menu/src/item.svelte diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 02a266c0..a7b3503d 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -1,7 +1,8 @@ + +{#each items as item (item.uid)} + + {#if item.type === 'divider'} + + + + {/if} + +{/each} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 670f947c..4b6a48ee 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -76,38 +76,15 @@ export type KMenuProps = { // TODO: slots overflowedIndicator 用于自定义 Menu 水平空间不足时的省略收缩的图标 // TODO: slots expandIcon 展开图标 -export type KItemType = KMenuItemType | DividerItem | SubMenuType | GroupItem +export type KItemType = KMenuItemType -export type KMenuItemType = { - /** - * TODO: 菜单图标 - */ - icon?: string - /** - * TODO: 菜单项标题 - */ - label?: string - /** - * TODO: item 的唯一标志 - */ - uid?: string - /** - * TODO: 设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) - */ - title?: string - /** - * TODO: 是否禁用 - * @default false - */ - disabled?: boolean +export type SubMenuType = { /** * TODO: 展示错误状态样式 * @default false */ - danger?: boolean -} - -export type SubMenuType = { + danger?: boolean, + type?: 'group' | 'divider', /** * TODO: 菜单图标 */ @@ -142,29 +119,5 @@ export type SubMenuType = { // TODO: onTitleClick 点击子菜单标题 -export type GroupItem = { - type?: 'group', // Must have - /** - * TODO: 分组标题 - */ - label?: string - /** - * TODO: item 的唯一标志 - */ - uid?: string - /** - * TODO: 分组的菜单项 - */ - children?: KItemType[], -}; - -export type DividerItem = { - type?: 'divider', // Must have - /** - * TODO: item 的唯一标志 - */ - uid?: string -}; - // TODO: Items Slots slots label 分组标题 // TODO: Items Slots slots icon 菜单图标 From 8a4f7f9c25ef142d4a06c264509c125e086471f1 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Tue, 16 Apr 2024 11:18:37 +0800 Subject: [PATCH 05/39] wip: recursive slots and dynamic context --- components/Menu/src/index.svelte | 54 +++++++++++++++--------- components/Menu/src/index.ts | 12 +++--- components/Menu/src/item.svelte | 59 ++++++++++++++++++++++----- components/Menu/src/types.d.ts | 70 +++++++++++++++++++++----------- components/Menu/src/utils.ts | 14 +++++++ utils/src/index.ts | 3 +- utils/src/symbol-key.ts | 1 + 7 files changed, 153 insertions(+), 60 deletions(-) create mode 100644 components/Menu/src/utils.ts diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index a7b3503d..e5f008ce 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -1,30 +1,46 @@
- {#if mode !== 'horizontal'} - - {/if} +
diff --git a/components/Menu/src/index.ts b/components/Menu/src/index.ts index 0ac11645..acb9e54b 100644 --- a/components/Menu/src/index.ts +++ b/components/Menu/src/index.ts @@ -6,9 +6,9 @@ export { MenuItem as KMenuItem }; export default Menu; export type { - KMenuProps, - DividerItem, - GroupItem, - SubMenuType, - KMenuItemType -} from './types' + KMenuInstanceOption, + KMenuItemProps, + KMenuInstance, + KMenuProps, + SubMenuType +} from './types'; diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index b4ef87e2..ad037486 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,15 +1,54 @@ -{#each items as item (item.uid)} - - {#if item.type === 'divider'} - +{#each items as it (it.uid)} +
+ + +
+ {it.label} + +
- - {/if} -
+ + {#if it.children && it.children.length} + + + + +
+ {item.label} + +
+ +
+
+
+ {/if} +
{/each} + diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 4b6a48ee..f608325f 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -1,70 +1,89 @@ /// import type { ClassValue } from 'clsx'; +export type KMenuInstanceOption = { + expandIcon?: string; + inlineIndent?: number; + inlineCollapsed?: number; + mode?: `vertical` | `horizontal` | `inline`; + openUids?: string[]; + overflowedIndicator?: string; + selectedUids?: string[]; + selectable?: boolean; + subMenuCloseDelay?: number; + subMenuOpenDelay?: number; + theme?: 'light' | 'dark'; + triggerSubMenuAction?: 'hover' | 'click'; +} +export type KMenuInstance = { + __propHandleEvtMap: Array<(props: Record) => void> + __dynamicProps: KMenuInstanceOption, +} + export type KMenuProps = { /** * TODO: 🎯 展开图标 * @default 'i-carbon-chevron-down' */ - expandIcon?: string + expandIcon?: string; /** * TODO: inline 模式的菜单缩进宽度 * @default 24 */ - inlineIndent?: number + inlineIndent?: number; /** * TODO: inline 时菜单是否收起状态 (指显示图标的mini模式和展开到常规模式) * @default 24 */ - inlineCollapsed?: number + inlineCollapsed?: number; /** * TODO: 🎯 菜单内容 */ - items: KItemType[] + // items: KItemType[] /** * TODO: 🎯 菜单类型,现在支持垂直、水平、和内嵌模式三种 * `vertical` 和 `inline` 的区别在于 `vertical` 子菜单以 popover 形式出现 * @default `vertical` */ - mode?: `vertical` | `horizontal` | `inline` + mode?: `vertical` | `horizontal` | `inline`; /** * TODO: 当前展开的 SubMenu 菜单项 key 数组 * @default `[]` */ - openUids?: string[] + openUids?: string[]; /** * TODO: 🎯 用于自定义 Menu 水平空间不足时的省略收缩的图标 */ - overflowedIndicator?: string + overflowedIndicator?: string; /** * TODO: 当前选中的菜单项 key 数组 * @default `[]` */ - selectedUids?: string[] + selectedUids?: string[]; /** * TODO: 是否允许选中(为 false, 仅不触发 select事件) * @default false */ - selectable?: boolean + selectable?: boolean; /** * TODO: 🎯 用户鼠标离开子菜单后关闭延时,单位:毫秒 * @default 100ms */ - subMenuCloseDelay?: boolean + subMenuCloseDelay?: number; /** * TODO: 🎯 用户鼠标进入子菜单后开启延时,单位:毫秒 * @default 0 */ - subMenuOpenDelay?: number + subMenuOpenDelay?: number; /** * TODO: 主题 * @default 'light' */ - theme?: 'light' | 'dark' + theme?: 'light' | 'dark'; /** * TODO: 🎯 SubMenu 展开/关闭的触发行为(非 inline 模式) * @default 'hover' */ - triggerSubMenuAction?: 'hover' | 'click' + triggerSubMenuAction?: 'hover' | 'click'; cls: ClassValue; attrs: Record; }; @@ -76,45 +95,48 @@ export type KMenuProps = { // TODO: slots overflowedIndicator 用于自定义 Menu 水平空间不足时的省略收缩的图标 // TODO: slots expandIcon 展开图标 -export type KItemType = KMenuItemType - +export type KMenuItemProps = { + items: SubMenuType[] + cls: ClassValue; + attrs: Record; +} export type SubMenuType = { /** * TODO: 展示错误状态样式 * @default false */ - danger?: boolean, - type?: 'group' | 'divider', + danger?: boolean; + type?: 'group' | 'divider'; /** * TODO: 菜单图标 */ - icon?: string + icon?: string; /** * TODO: 菜单项标题 */ - label?: string + label?: string; /** * TODO: item 的唯一标志 */ - uid?: string + uid?: string; /** * TODO: 是否禁用 * @default false */ - disabled?: boolean + disabled?: boolean; /** * TODO: 设置子菜单的主题,默认从 Menu 上继承 * @default 'light' */ - theme?: 'light' | 'dark' + theme?: 'light' | 'dark'; /** * TODO: 子菜单的菜单项 */ - children?: KItemType[] + children?: KItemType[]; /** * TODO: 子菜单样式,mode="inline" 时无效 */ - popupClassName?: string + popupClassName?: string; }; // TODO: onTitleClick 点击子菜单标题 diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts new file mode 100644 index 00000000..7a2469b1 --- /dev/null +++ b/components/Menu/src/utils.ts @@ -0,0 +1,14 @@ +import type { KMenuInstance, KMenuInstanceOption } from "./types"; + + +export const createKMenu = (options: KMenuInstanceOption):KMenuInstance => { + return { + /** + * @internal + */ + __propHandleEvtMap: [], + __dynamicProps: { + ...options + } + } +} diff --git a/utils/src/index.ts b/utils/src/index.ts index 0b708508..8c1567ec 100644 --- a/utils/src/index.ts +++ b/utils/src/index.ts @@ -15,6 +15,7 @@ export { tabsKey, dropDownKey, descriptionsKey, - segmentedKey + segmentedKey, + menuKey, } from './symbol-key'; export * from './dom'; diff --git a/utils/src/symbol-key.ts b/utils/src/symbol-key.ts index 8cdc87bf..b67c2edd 100644 --- a/utils/src/symbol-key.ts +++ b/utils/src/symbol-key.ts @@ -20,3 +20,4 @@ export const dropDownKey = KSymbolKey('dropDown'); export const tabsKey = KSymbolKey('tabs'); export const descriptionsKey = KSymbolKey('descriptions'); export const segmentedKey = KSymbolKey('segmented'); +export const menuKey = KSymbolKey('menu'); From 8292b95d106a76deb29bed13d152cf35f23a86c3 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Tue, 16 Apr 2024 18:33:44 +0800 Subject: [PATCH 06/39] wip: initial drawing of menu component inline mode --- components/Menu/package.json | 1 + components/Menu/src/index.svelte | 18 ++- components/Menu/src/item.svelte | 190 ++++++++++++++++++++++++----- components/Menu/src/types.d.ts | 24 ++-- preset/src/rules/index.ts | 2 + preset/src/rules/src/menu.ts | 7 ++ preset/src/shortcuts/src/common.ts | 1 + preset/src/shortcuts/src/menu.ts | 33 ++++- 8 files changed, 234 insertions(+), 42 deletions(-) create mode 100644 preset/src/rules/src/menu.ts diff --git a/components/Menu/package.json b/components/Menu/package.json index 34c658ac..bddd7f1e 100644 --- a/components/Menu/package.json +++ b/components/Menu/package.json @@ -34,6 +34,7 @@ "dependencies": { "@ikun-ui/icon": "workspace:*", "@ikun-ui/utils": "workspace:*", + "@ikun-ui/divider": "workspace:*", "baiwusanyu-utils": "^1.0.18", "clsx": "^2.0.0", "svelte": "^4.2.7" diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index e5f008ce..30568432 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -7,7 +7,7 @@ export let triggerSubMenuAction: KMenuProps['triggerSubMenuAction'] = 'hover'; export let subMenuCloseDelay: KMenuProps['subMenuCloseDelay'] = 100; export let subMenuOpenDelay: KMenuProps['subMenuOpenDelay'] = 0; - // export let items: KMenuProps['items'] = []; + export let inlineIndent: KMenuProps['inlineIndent'] = 24 export let expandIcon: KMenuProps['expandIcon'] = 'i-carbon-chevron-down'; export let overflowedIndicator: KMenuProps['overflowedIndicator'] = 'i-carbon-overflow-menu-horizontal'; @@ -22,6 +22,9 @@ expandIcon, overflowedIndicator, mode, + inlineIndent, + cls, + attrs, }) setContext(menuKey, menuInst); $: { @@ -33,14 +36,21 @@ expandIcon, overflowedIndicator, mode, + inlineIndent, + cls, + attrs, }); }); } const prefixCls = getPrefixCls('menu'); - $: cnames = clsx(prefixCls, cls); + $: cnames = clsx( + prefixCls, + `${prefixCls}-${mode}`, + cls + ); -
+
    -
+ diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index ad037486..a9f8b39e 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,54 +1,186 @@ -{#each items as it (it.uid)} -
- - -
- {it.label} - -
- -
- {#if it.children && it.children.length} - - - - -
- {item.label} - -
+{#each itemsList as it (it.uid)} + {#if it.type !== 'divider'} +
  • handleSelect(it)} + aria-hidden="true" + style:padding-left={`${(ctxProps.inlineIndent || 24 ) * getLevel(it, level)}px`} + class={cnames(it)} + {...$$restProps} + {...attrs}> + +
    + + {#if it.icon} + + + {/if} + + {it.label} +
    + {#if hasSub(it) && !isGroup(it)} + + + - - + {/if} +
    + + +
  • + + {#if (hasSub(it) && it.open) || isGroup(it)} + + + + + + +
    + + {#if item.icon} + + + {/if} + + self {item.label} +
    + + {#if hasSub(item) && !isGroup(item)} + + + + + {/if} + +
    + +
    +
    +
    {/if} -
    + {:else} + + {/if} {/each} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index f608325f..2c299914 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -3,7 +3,7 @@ import type { ClassValue } from 'clsx'; export type KMenuInstanceOption = { expandIcon?: string; inlineIndent?: number; - inlineCollapsed?: number; + inlineCollapsed?: boolean; mode?: `vertical` | `horizontal` | `inline`; openUids?: string[]; overflowedIndicator?: string; @@ -13,6 +13,8 @@ export type KMenuInstanceOption = { subMenuOpenDelay?: number; theme?: 'light' | 'dark'; triggerSubMenuAction?: 'hover' | 'click'; + cls?: ClassValue; + attrs?: Record; } export type KMenuInstance = { __propHandleEvtMap: Array<(props: Record) => void> @@ -32,13 +34,9 @@ export type KMenuProps = { inlineIndent?: number; /** * TODO: inline 时菜单是否收起状态 (指显示图标的mini模式和展开到常规模式) - * @default 24 - */ - inlineCollapsed?: number; - /** - * TODO: 🎯 菜单内容 + * @default false */ - // items: KItemType[] + inlineCollapsed?: boolean; /** * TODO: 🎯 菜单类型,现在支持垂直、水平、和内嵌模式三种 * `vertical` 和 `inline` 的区别在于 `vertical` 子菜单以 popover 形式出现 @@ -96,6 +94,10 @@ export type KMenuProps = { // TODO: slots expandIcon 展开图标 export type KMenuItemProps = { + /** + * @internal + */ + level: number items: SubMenuType[] cls: ClassValue; attrs: Record; @@ -132,14 +134,20 @@ export type SubMenuType = { /** * TODO: 子菜单的菜单项 */ - children?: KItemType[]; + children?: SubMenuType[]; /** * TODO: 子菜单样式,mode="inline" 时无效 */ popupClassName?: string; + [property: string]: any }; // TODO: onTitleClick 点击子菜单标题 // TODO: Items Slots slots label 分组标题 // TODO: Items Slots slots icon 菜单图标 + + +// TODO: 高度动画 +// TODO: 缩略文字 +// TODO: 背景色随着层级加深 diff --git a/preset/src/rules/index.ts b/preset/src/rules/index.ts index 41fd9015..456907d8 100644 --- a/preset/src/rules/index.ts +++ b/preset/src/rules/index.ts @@ -18,6 +18,7 @@ import { carouselRules } from './src/carousel'; import { skeletonRules } from './src/skeleton'; import { colorPickerRules } from './src/color-picker'; import { timelineRules } from './src/timeline'; +import { menuRules } from './src/menu'; import { baseRules } from './src/base'; declare type dynamicRulesFunc = (...args: any[]) => Array any)>; @@ -34,6 +35,7 @@ export const defaultRules = { ...carouselRules, ...skeletonRules, ...colorPickerRules, + ...menuRules, ...timelineRules, ...baseRules, ...getColCls(), diff --git a/preset/src/rules/src/menu.ts b/preset/src/rules/src/menu.ts new file mode 100644 index 00000000..488b3940 --- /dev/null +++ b/preset/src/rules/src/menu.ts @@ -0,0 +1,7 @@ +export const menuRules = { + 'k-menu-w': { width: 'calc(100% - 8px)' }, + 'k-menu-transition-c': { transition: 'color 0.3s' }, + 'k-menu-transition-o': { transition: 'opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),margin 0.3s,color 0.3s' }, + 'k-menu-transition-w': { transition: 'width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s' }, + 'k-menu-transition': { transition: 'border-color 0.3s,background 0.3s,padding 0.3s cubic-bezier(0.645, 0.045, 0.355, 1)' }, +}; diff --git a/preset/src/shortcuts/src/common.ts b/preset/src/shortcuts/src/common.ts index 36540024..44f00c14 100644 --- a/preset/src/shortcuts/src/common.ts +++ b/preset/src/shortcuts/src/common.ts @@ -29,6 +29,7 @@ export const commonShortcuts: UserShortcuts = { infcc: 'inline-flex justify-center items-center', 'bd-1': 'border-t-1 border-l-1 border-b-1 border-r-1', 'bdt-1': 'border-t-1 border-l-0 border-b-0 border-r-0', + 'bdr-1': 'border-t-0 border-l-0 border-b-0 border-r-1', 'bdl-1': 'border-l-1 border-t-0 border-b-0 border-r-0', 'bdb-1': 'border-l-0 border-t-0 border-b-1 border-r-0', 'bdlb-1': 'border-l-1 border-t-0 border-b-1 border-r-0', diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 624f842e..bd91ca5a 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -1,3 +1,34 @@ export const menuShortcuts: Record = { - 'k-menu': '' + 'k-menu': 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', + 'k-menu-item': 'box-border', + 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0', + 'k-menu-title-content': 'box-border k-menu-transition-c', + 'k-menu-title-content-i': 'm-is-10px k-menu-transition-o opacity-[1]', + 'k-menu-item-divider': 'my-0', + + + + 'k-menu-sub': 'border-none', + + + 'k-menu-horizontal': '', + 'k-menu-item-horizontal': '', + + + + + + 'k-menu-item-selected': 'ikun:20:bg-ikun-main text-ikun-main hover:(ikun:20:bg-ikun-main)', + 'k-menu-item-hover-ih': 'hover:(ikun:6:bg-ikun-black)', + 'k-menu-item-vh-child': 'justify-between', + + 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-item-vertical': '', + 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + + 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'rounded-8px active:(ikun:20:bg-ikun-main)', + 'k-menu-item-inline-group': 'k-menu-w k-menu-transition ' + + 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'rounded-8px ikun:50:text-black', }; From f1f00c5abcb1ee3b20ed365977992bf0c04b8a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:34:59 +0800 Subject: [PATCH 07/39] wip: KMenu component completes submenu expansion animation --- components/Menu/src/index.svelte | 29 ++--- components/Menu/src/index.ts | 10 +- components/Menu/src/item.svelte | 205 +++++++++++++------------------ components/Menu/src/types.d.ts | 23 ++-- components/Menu/src/utils.ts | 55 +++++++-- preset/src/rules/src/menu.ts | 15 ++- preset/src/shortcuts/src/menu.ts | 20 ++- utils/src/index.ts | 2 +- 8 files changed, 182 insertions(+), 177 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 30568432..022c1158 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -3,18 +3,21 @@ import { clsx } from 'clsx'; import type { KMenuProps } from './types'; import { setContext } from 'svelte'; - import { createKMenu } from "./utils"; + import { createKMenu, transitionIn, transitionOut } from './utils'; export let triggerSubMenuAction: KMenuProps['triggerSubMenuAction'] = 'hover'; export let subMenuCloseDelay: KMenuProps['subMenuCloseDelay'] = 100; export let subMenuOpenDelay: KMenuProps['subMenuOpenDelay'] = 0; - export let inlineIndent: KMenuProps['inlineIndent'] = 24 + export let inlineIndent: KMenuProps['inlineIndent'] = 24; export let expandIcon: KMenuProps['expandIcon'] = 'i-carbon-chevron-down'; export let overflowedIndicator: KMenuProps['overflowedIndicator'] = 'i-carbon-overflow-menu-horizontal'; export let mode: KMenuProps['mode'] = 'vertical'; export let cls: KMenuProps['cls'] = undefined; export let attrs: KMenuProps['attrs'] = {}; - + export let show: KMenuProps['show'] = true; + /** + * @internal + */ const menuInst = createKMenu({ triggerSubMenuAction, subMenuCloseDelay, @@ -24,8 +27,8 @@ mode, inlineIndent, cls, - attrs, - }) + attrs + }); setContext(menuKey, menuInst); $: { menuInst.__propHandleEvtMap.forEach((cb) => { @@ -38,19 +41,17 @@ mode, inlineIndent, cls, - attrs, + attrs }); }); } const prefixCls = getPrefixCls('menu'); - $: cnames = clsx( - prefixCls, - `${prefixCls}-${mode}`, - cls - ); + $: cnames = clsx(prefixCls, `${prefixCls}-${mode}`, cls); -
      - -
    +{#if show} +
      + +
    +{/if} diff --git a/components/Menu/src/index.ts b/components/Menu/src/index.ts index acb9e54b..f63e955e 100644 --- a/components/Menu/src/index.ts +++ b/components/Menu/src/index.ts @@ -6,9 +6,9 @@ export { MenuItem as KMenuItem }; export default Menu; export type { - KMenuInstanceOption, - KMenuItemProps, - KMenuInstance, - KMenuProps, - SubMenuType + KMenuInstanceOption, + KMenuItemProps, + KMenuInstance, + KMenuProps, + SubMenuType } from './types'; diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index a9f8b39e..6d2d4a1e 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,76 +1,61 @@ {#each itemsList as it (it.uid)} @@ -111,19 +102,16 @@
  • handleSelect(it)} aria-hidden="true" - style:padding-left={`${(ctxProps.inlineIndent || 24 ) * getLevel(it, level)}px`} + style:padding-left={`${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px`} class={cnames(it)} {...$$restProps} - {...attrs}> + {...attrs} + >
    {#if it.icon} - - + {/if} {it.label} @@ -131,56 +119,35 @@ {#if hasSub(it) && !isGroup(it)} - - + {/if} - -
  • - - {#if (hasSub(it) && it.open) || isGroup(it)} - - - - - - -
    - - {#if item.icon} - - - {/if} - - self {item.label} -
    - - {#if hasSub(item) && !isGroup(item)} - - - - - {/if} - -
    - -
    -
    -
    - {/if} - {:else} + + + + + +
    + + {#if item.icon} + + {/if} + + self {item.label} +
    + + {#if hasSub(item) && !isGroup(item)} + + + + {/if} +
    +
    +
    +
    + {:else} {/if} {/each} - diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 2c299914..fa64d3df 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -15,11 +15,11 @@ export type KMenuInstanceOption = { triggerSubMenuAction?: 'hover' | 'click'; cls?: ClassValue; attrs?: Record; -} +}; export type KMenuInstance = { - __propHandleEvtMap: Array<(props: Record) => void> - __dynamicProps: KMenuInstanceOption, -} + __propHandleEvtMap: Array<(props: Record) => void>; + __dynamicProps: KMenuInstanceOption; +}; export type KMenuProps = { /** @@ -82,6 +82,10 @@ export type KMenuProps = { * @default 'hover' */ triggerSubMenuAction?: 'hover' | 'click'; + /** + * @internal + */ + show: boolean; cls: ClassValue; attrs: Record; }; @@ -97,11 +101,11 @@ export type KMenuItemProps = { /** * @internal */ - level: number - items: SubMenuType[] + level: number; + items: SubMenuType[]; cls: ClassValue; attrs: Record; -} +}; export type SubMenuType = { /** * TODO: 展示错误状态样式 @@ -139,7 +143,7 @@ export type SubMenuType = { * TODO: 子菜单样式,mode="inline" 时无效 */ popupClassName?: string; - [property: string]: any + [property: string]: any; }; // TODO: onTitleClick 点击子菜单标题 @@ -147,7 +151,6 @@ export type SubMenuType = { // TODO: Items Slots slots label 分组标题 // TODO: Items Slots slots icon 菜单图标 - -// TODO: 高度动画 // TODO: 缩略文字 // TODO: 背景色随着层级加深 +// TODO: 菜单样式 diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index 7a2469b1..2aa786a6 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -1,14 +1,47 @@ -import type { KMenuInstance, KMenuInstanceOption } from "./types"; +import type { KMenuInstance, KMenuInstanceOption } from './types'; +export const createKMenu = (options: KMenuInstanceOption): KMenuInstance => { + return { + /** + * @internal + */ + __propHandleEvtMap: [], + __dynamicProps: { + ...options + } + }; +}; -export const createKMenu = (options: KMenuInstanceOption):KMenuInstance => { - return { - /** - * @internal - */ - __propHandleEvtMap: [], - __dynamicProps: { - ...options - } - } +export function transitionIn(node: HTMLElement) { + return { + duration: 300, + tick: (t: number) => { + if (t === 0) { + node.style.overflow = 'hidden'; + node.style.transition = 'height 0.3s'; + node.style.height = '0'; + } else if (t === 100) { + node.style.removeProperty('height'); + } else { + node.style.height = node.scrollHeight + 'px'; + } + } + }; +} + +export function transitionOut(node: HTMLElement) { + return { + duration: 300, + tick: (t: number) => { + if (t === 0) { + node.style.overflow = 'hidden'; + node.style.transition = 'height 0.3s'; + node.style.height = node.scrollHeight + 'px'; + } else if (t === 100) { + node.style.removeProperty('height'); + } else { + node.style.height = '0'; + } + } + }; } diff --git a/preset/src/rules/src/menu.ts b/preset/src/rules/src/menu.ts index 488b3940..86ec9cd6 100644 --- a/preset/src/rules/src/menu.ts +++ b/preset/src/rules/src/menu.ts @@ -1,7 +1,12 @@ export const menuRules = { - 'k-menu-w': { width: 'calc(100% - 8px)' }, - 'k-menu-transition-c': { transition: 'color 0.3s' }, - 'k-menu-transition-o': { transition: 'opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),margin 0.3s,color 0.3s' }, - 'k-menu-transition-w': { transition: 'width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s' }, - 'k-menu-transition': { transition: 'border-color 0.3s,background 0.3s,padding 0.3s cubic-bezier(0.645, 0.045, 0.355, 1)' }, + 'k-menu-w': { width: 'calc(100% - 8px)' }, + 'k-menu-transition-c': { transition: 'color 0.3s' }, + 'k-menu-transition-o': { + transition: 'opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),margin 0.3s,color 0.3s' + }, + 'k-menu-transition-w': { transition: 'width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s' }, + 'k-menu-transition': { + transition: + 'border-color 0.3s,background 0.3s,padding 0.3s cubic-bezier(0.645, 0.045, 0.355, 1)' + } }; diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index bd91ca5a..36c525ed 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -1,23 +1,17 @@ export const menuShortcuts: Record = { - 'k-menu': 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', - 'k-menu-item': 'box-border', + 'k-menu': + 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', + 'k-menu-item': 'box-border select-none', 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0', 'k-menu-title-content': 'box-border k-menu-transition-c', 'k-menu-title-content-i': 'm-is-10px k-menu-transition-o opacity-[1]', 'k-menu-item-divider': 'my-0', - - 'k-menu-sub': 'border-none', - 'k-menu-horizontal': '', 'k-menu-item-horizontal': '', - - - - 'k-menu-item-selected': 'ikun:20:bg-ikun-main text-ikun-main hover:(ikun:20:bg-ikun-main)', 'k-menu-item-hover-ih': 'hover:(ikun:6:bg-ikun-black)', 'k-menu-item-vh-child': 'justify-between', @@ -25,10 +19,12 @@ export const menuShortcuts: Record = { 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', 'k-menu-item-vertical': '', - 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + + 'k-menu-item-inline': + 'cursor-pointer k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + 'rounded-8px active:(ikun:20:bg-ikun-main)', - 'k-menu-item-inline-group': 'k-menu-w k-menu-transition ' + + 'k-menu-item-inline-group': + 'k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + - 'rounded-8px ikun:50:text-black', + 'rounded-8px ikun:50:text-black' }; diff --git a/utils/src/index.ts b/utils/src/index.ts index 8c1567ec..7d2a5ee1 100644 --- a/utils/src/index.ts +++ b/utils/src/index.ts @@ -16,6 +16,6 @@ export { dropDownKey, descriptionsKey, segmentedKey, - menuKey, + menuKey } from './symbol-key'; export * from './dom'; From 2ba32332d99cde9f4f418f75b388e2a3eafb44cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Tue, 16 Apr 2024 23:35:28 +0800 Subject: [PATCH 08/39] wip: KMenu component completes submenu expansion animation --- components/Menu/src/item.svelte | 38 +++++++++++++++++--------------- components/Menu/src/types.d.ts | 1 - preset/src/shortcuts/src/menu.ts | 10 ++++----- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 6d2d4a1e..05adb2c3 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -108,18 +108,19 @@ {...attrs} > -
    - - {#if it.icon} - - {/if} - - {it.label} -
    + + {#if it.icon} + + {/if} + + {it.label} {#if hasSub(it) && !isGroup(it)} - + {/if}
    @@ -129,18 +130,19 @@ -
    - - {#if item.icon} - - {/if} - - self {item.label} -
    + + {#if item.icon} + + {/if} + + self {item.label} {#if hasSub(item) && !isGroup(item)} - + {/if}
    diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index fa64d3df..1a4cff35 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -151,6 +151,5 @@ export type SubMenuType = { // TODO: Items Slots slots label 分组标题 // TODO: Items Slots slots icon 菜单图标 -// TODO: 缩略文字 // TODO: 背景色随着层级加深 // TODO: 菜单样式 diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 36c525ed..207a0b7f 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -2,9 +2,9 @@ export const menuShortcuts: Record = { 'k-menu': 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', 'k-menu-item': 'box-border select-none', - 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0', - 'k-menu-title-content': 'box-border k-menu-transition-c', - 'k-menu-title-content-i': 'm-is-10px k-menu-transition-o opacity-[1]', + 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0 min-w-14px', + 'k-menu-title-content': 'truncate box-border k-menu-transition-c', + 'k-menu-title-content-i': 'm-is-6px m-ie-6px k-menu-transition-o opacity-[1] truncate', 'k-menu-item-divider': 'my-0', 'k-menu-sub': 'border-none', @@ -21,10 +21,10 @@ export const menuShortcuts: Record = { 'k-menu-item-vertical': '', 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-style-position ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + 'rounded-8px active:(ikun:20:bg-ikun-main)', 'k-menu-item-inline-group': 'k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-style-position truncate ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-style-position ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + 'rounded-8px ikun:50:text-black' }; From ea22ff81a2c1d04473e7cde60eb4c666e05515d6 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Wed, 17 Apr 2024 09:20:22 +0800 Subject: [PATCH 09/39] wip: fix expend animation --- components/Menu/src/index.svelte | 4 ---- components/Menu/src/types.d.ts | 10 ++-------- components/Menu/src/utils.ts | 11 +++++------ 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 022c1158..014dc5ce 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -9,8 +9,6 @@ export let subMenuOpenDelay: KMenuProps['subMenuOpenDelay'] = 0; export let inlineIndent: KMenuProps['inlineIndent'] = 24; export let expandIcon: KMenuProps['expandIcon'] = 'i-carbon-chevron-down'; - export let overflowedIndicator: KMenuProps['overflowedIndicator'] = - 'i-carbon-overflow-menu-horizontal'; export let mode: KMenuProps['mode'] = 'vertical'; export let cls: KMenuProps['cls'] = undefined; export let attrs: KMenuProps['attrs'] = {}; @@ -23,7 +21,6 @@ subMenuCloseDelay, subMenuOpenDelay, expandIcon, - overflowedIndicator, mode, inlineIndent, cls, @@ -37,7 +34,6 @@ subMenuCloseDelay, subMenuOpenDelay, expandIcon, - overflowedIndicator, mode, inlineIndent, cls, diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 1a4cff35..c37c971d 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -6,7 +6,6 @@ export type KMenuInstanceOption = { inlineCollapsed?: boolean; mode?: `vertical` | `horizontal` | `inline`; openUids?: string[]; - overflowedIndicator?: string; selectedUids?: string[]; selectable?: boolean; subMenuCloseDelay?: number; @@ -23,12 +22,12 @@ export type KMenuInstance = { export type KMenuProps = { /** - * TODO: 🎯 展开图标 + * TODO: 👀 展开图标 * @default 'i-carbon-chevron-down' */ expandIcon?: string; /** - * TODO: inline 模式的菜单缩进宽度 + * TODO: 👀 inline 模式的菜单缩进宽度 * @default 24 */ inlineIndent?: number; @@ -48,10 +47,6 @@ export type KMenuProps = { * @default `[]` */ openUids?: string[]; - /** - * TODO: 🎯 用于自定义 Menu 水平空间不足时的省略收缩的图标 - */ - overflowedIndicator?: string; /** * TODO: 当前选中的菜单项 key 数组 * @default `[]` @@ -94,7 +89,6 @@ export type KMenuProps = { // TODO: onOpenChange SubMenu 展开/关闭的回调 // TODO: onSelect 被选中时调用(点击子菜单标题不触发) -// TODO: slots overflowedIndicator 用于自定义 Menu 水平空间不足时的省略收缩的图标 // TODO: slots expandIcon 展开图标 export type KMenuItemProps = { diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index 2aa786a6..e582f738 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -20,7 +20,7 @@ export function transitionIn(node: HTMLElement) { node.style.overflow = 'hidden'; node.style.transition = 'height 0.3s'; node.style.height = '0'; - } else if (t === 100) { + } else if (t === 1) { node.style.removeProperty('height'); } else { node.style.height = node.scrollHeight + 'px'; @@ -30,14 +30,13 @@ export function transitionIn(node: HTMLElement) { } export function transitionOut(node: HTMLElement) { + const orgHeight = node.scrollHeight return { duration: 300, tick: (t: number) => { - if (t === 0) { - node.style.overflow = 'hidden'; - node.style.transition = 'height 0.3s'; - node.style.height = node.scrollHeight + 'px'; - } else if (t === 100) { + if (t <= 1 && t >= 0.9) { + node.style.height = orgHeight + 'px'; + } else if (t === 0) { node.style.removeProperty('height'); } else { node.style.height = '0'; From f6255544d1eef2ffe59fdb29b1d758d488dc6b56 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Wed, 17 Apr 2024 10:37:10 +0800 Subject: [PATCH 10/39] wip: complete the selected style of the KMenu component submenu --- components/Menu/src/item.svelte | 49 ++++++++++++++++++++++++++++---- components/Menu/src/types.d.ts | 29 +++++++++++++++---- preset/src/shortcuts/src/menu.ts | 3 +- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 05adb2c3..9c64240d 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,5 +1,5 @@ -{#each itemsList as it (it.uid)} +{#each itemsList as it, index (it.uid)} {#if it.type !== 'divider'}
  • handleSelect(it)} @@ -127,7 +163,10 @@
  • - + handleSelectedRecursion(e, index)} + items={it.children} + level={getLevel(it, level) + 1}> diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index c37c971d..6eeeca44 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -106,17 +106,20 @@ export type SubMenuType = { * @default false */ danger?: boolean; + /** + * TODO: 👀 展示為分組或分割綫 + */ type?: 'group' | 'divider'; /** - * TODO: 菜单图标 + * TODO: 👀 菜单图标 */ icon?: string; /** - * TODO: 菜单项标题 + * TODO: 👀 菜单项标题 */ label?: string; /** - * TODO: item 的唯一标志 + * TODO: 👀 item 的唯一标志 */ uid?: string; /** @@ -130,13 +133,29 @@ export type SubMenuType = { */ theme?: 'light' | 'dark'; /** - * TODO: 子菜单的菜单项 + * TODO: 设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) + */ + title?: string + /** + * TODO: 👀 子菜单的菜单项 */ children?: SubMenuType[]; /** * TODO: 子菜单样式,mode="inline" 时无效 */ popupClassName?: string; + /** + * @internal + */ + selected?: boolean + /** + * @internal + */ + open?: boolean + /** + * @internal + */ + selectedDeps: Set [property: string]: any; }; @@ -146,4 +165,4 @@ export type SubMenuType = { // TODO: Items Slots slots icon 菜单图标 // TODO: 背景色随着层级加深 -// TODO: 菜单样式 + diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 207a0b7f..26c20317 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -3,7 +3,7 @@ export const menuShortcuts: Record = { 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', 'k-menu-item': 'box-border select-none', 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0 min-w-14px', - 'k-menu-title-content': 'truncate box-border k-menu-transition-c', + 'k-menu-title-content': 'truncate box-border k-menu-transition-c select-none', 'k-menu-title-content-i': 'm-is-6px m-ie-6px k-menu-transition-o opacity-[1] truncate', 'k-menu-item-divider': 'my-0', @@ -13,6 +13,7 @@ export const menuShortcuts: Record = { 'k-menu-item-horizontal': '', 'k-menu-item-selected': 'ikun:20:bg-ikun-main text-ikun-main hover:(ikun:20:bg-ikun-main)', + 'k-menu-item-selected-ih': 'text-ikun-main', 'k-menu-item-hover-ih': 'hover:(ikun:6:bg-ikun-black)', 'k-menu-item-vh-child': 'justify-between', From 9f39ad660d3cefb60b3fbe9b11b40ad9fa95cbf9 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Wed, 17 Apr 2024 10:58:13 +0800 Subject: [PATCH 11/39] wip: KMenu component completes incremental changes in submenu background color --- components/Menu/src/index.svelte | 2 -- components/Menu/src/item.svelte | 11 +++++++++-- components/Menu/src/types.d.ts | 4 +--- preset/src/shortcuts/src/menu.ts | 5 ++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 014dc5ce..c2917811 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -23,7 +23,6 @@ expandIcon, mode, inlineIndent, - cls, attrs }); setContext(menuKey, menuInst); @@ -36,7 +35,6 @@ expandIcon, mode, inlineIndent, - cls, attrs }); }); diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 9c64240d..2c19eb5b 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -130,7 +130,14 @@ }); }; const dividerCls = clsx(`${prefixCls}-divider`); - $: subMenuCls = clsx(`${menuPrefixCls}-sub`, ctxProps.cls); + const subMenuCls = (isGroup: boolean) => { + return clsx( + `${menuPrefixCls}-sub`, + { + [`${menuPrefixCls}-sub-bg`]: !isGroup + } + ); + } {#each itemsList as it, index (it.uid)} @@ -162,7 +169,7 @@ - + handleSelectedRecursion(e, index)} items={it.children} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 6eeeca44..a7b72501 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -12,7 +12,6 @@ export type KMenuInstanceOption = { subMenuOpenDelay?: number; theme?: 'light' | 'dark'; triggerSubMenuAction?: 'hover' | 'click'; - cls?: ClassValue; attrs?: Record; }; export type KMenuInstance = { @@ -155,7 +154,7 @@ export type SubMenuType = { /** * @internal */ - selectedDeps: Set + selectedDeps?: Set [property: string]: any; }; @@ -164,5 +163,4 @@ export type SubMenuType = { // TODO: Items Slots slots label 分组标题 // TODO: Items Slots slots icon 菜单图标 -// TODO: 背景色随着层级加深 diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 26c20317..29c5e6b9 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -1,13 +1,16 @@ export const menuShortcuts: Record = { 'k-menu': 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', + + 'k-menu-item': 'box-border select-none', 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0 min-w-14px', 'k-menu-title-content': 'truncate box-border k-menu-transition-c select-none', 'k-menu-title-content-i': 'm-is-6px m-ie-6px k-menu-transition-o opacity-[1] truncate', 'k-menu-item-divider': 'my-0', - 'k-menu-sub': 'border-none', + 'k-menu-sub': 'border-none bg-transparent', + 'k-menu-sub-bg': 'ikun:2:bg-black', 'k-menu-horizontal': '', 'k-menu-item-horizontal': '', From f05ed4404daaa09d4d7e60cd8ba22cda61b238d9 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Wed, 17 Apr 2024 11:45:00 +0800 Subject: [PATCH 12/39] wip: KMenu component completes inline mode default submenu expansion --- components/Menu/src/index.svelte | 11 +++++++- components/Menu/src/item.svelte | 34 ++++++++++++++-------- components/Menu/src/types.d.ts | 48 +++++++++++++++++++++----------- components/Menu/src/utils.ts | 2 -- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index c2917811..56727401 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -12,6 +12,8 @@ export let mode: KMenuProps['mode'] = 'vertical'; export let cls: KMenuProps['cls'] = undefined; export let attrs: KMenuProps['attrs'] = {}; + export let selectedUids: KMenuProps['selectedUids'] = []; + export let openUids: KMenuProps['openUids'] = []; export let show: KMenuProps['show'] = true; /** * @internal @@ -23,6 +25,8 @@ expandIcon, mode, inlineIndent, + openUids, + selectedUids, attrs }); setContext(menuKey, menuInst); @@ -35,6 +39,8 @@ expandIcon, mode, inlineIndent, + openUids, + selectedUids, attrs }); }); @@ -45,7 +51,10 @@ {#if show} -
      +
      {/if} diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 2c19eb5b..86c1a731 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -21,20 +21,36 @@ return lv; }; + let itemsList = items; + $: { + itemsList = items; + // itemsList = initOpenSelectedStatus() + } + function initOpenSelectedStatus(list = itemsList) { + return list.map((value) => { + const defaultSelected = ctxProps.selectedUids?.includes(value.uid || '') + const defaultOpen = ctxProps.openUids?.includes(value.uid || '') + value.selected = defaultSelected + value.open = defaultOpen + if (hasSub(value)) { + value.children = initOpenSelectedStatus(value.children!); + } + return value; + }); + } const menuCtx = getContext(menuKey) as KMenuInstance; let ctxProps: KMenuInstanceOption = {}; function updatedCtxProps(props: Record) { ctxProps = { ...props }; + itemsList = initOpenSelectedStatus() } if (menuCtx) { ctxProps = { ...menuCtx.__dynamicProps }; + itemsList = initOpenSelectedStatus() + console.log(itemsList) menuCtx.__propHandleEvtMap.push(updatedCtxProps); } - let itemsList = items; - $: { - itemsList = items; - } function handleSelectedRecursion(e: CustomEvent, index: number){ const { selected, uid } = e.detail @@ -66,12 +82,10 @@ if (value.uid === it.uid && !isGroup(it)) { // set selected value.selected = !value.selected; - value.selected = ctxProps.selectedUids?.includes(value.uid || '') || value.selected; // set open if (hasSub(it)) { value.open = !value.open; value.selected = false - value.open = ctxProps.openUids?.includes(value.uid || '') || value.open; } /** * @internal @@ -100,15 +114,13 @@ [`${prefixCls}-${ctxProps.mode}-group`]: isGroup(it), [`${prefixCls}-${ctxProps.mode}`]: !isGroup(it), [`${prefixCls}-selected`]: - !isGroup(it) && !hasSub(it) && isNotHorizontal() && (ctxProps.selectedUids?.includes(it.uid || '') || - it.selected), + !isGroup(it) && !hasSub(it) && isNotHorizontal() && (it.selected), [`${prefixCls}-selected-ih`]: - !isGroup(it) && hasSub(it) && isNotHorizontal() && (ctxProps.selectedUids?.includes(it.uid || '') || - it.selected), + !isGroup(it) && hasSub(it) && isNotHorizontal() && (it.selected), [`${prefixCls}-hover-ih`]: !isGroup(it) && isNotHorizontal() && - !(ctxProps.selectedUids?.includes(it.uid || '') || it.selected), + !(it.selected), [`${prefixCls}-vh-child`]: !isGroup(it) && isNotHorizontal() && hasSub(it) }, cls diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index a7b72501..95525647 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -42,27 +42,31 @@ export type KMenuProps = { */ mode?: `vertical` | `horizontal` | `inline`; /** - * TODO: 当前展开的 SubMenu 菜单项 key 数组 + * TODO: 👀 当前展开的 SubMenu 菜单项 key 数组 inline + * TODO: 当前展开的 SubMenu 菜单项 key 数组 vertical + * TODO: 当前展开的 SubMenu 菜单项 key 数组 horizontal * @default `[]` */ openUids?: string[]; /** - * TODO: 当前选中的菜单项 key 数组 + * TODO: 🎯 当前选中的菜单项 key 数组(子菜单只高亮,不展开) * @default `[]` */ selectedUids?: string[]; /** - * TODO: 是否允许选中(为 false, 仅不触发 select事件) + * TODO: 🎯 是否允许选中(为 false, 点击不高亮,不触发 select事件) inline + * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) vertical + * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) horizontal * @default false */ selectable?: boolean; /** - * TODO: 🎯 用户鼠标离开子菜单后关闭延时,单位:毫秒 + * TODO: 用户鼠标离开子菜单后关闭延时,单位:毫秒(非 inline 模式, hover触发) * @default 100ms */ subMenuCloseDelay?: number; /** - * TODO: 🎯 用户鼠标进入子菜单后开启延时,单位:毫秒 + * TODO: 用户鼠标进入子菜单后开启延时,单位:毫秒(非 inline 模式, hover触发) * @default 0 */ subMenuOpenDelay?: number; @@ -72,23 +76,31 @@ export type KMenuProps = { */ theme?: 'light' | 'dark'; /** - * TODO: 🎯 SubMenu 展开/关闭的触发行为(非 inline 模式) + * TODO: SubMenu 展开/关闭的触发行为(非 inline 模式) * @default 'hover' */ triggerSubMenuAction?: 'hover' | 'click'; + cls: ClassValue; + attrs: Record; /** * @internal */ show: boolean; - cls: ClassValue; - attrs: Record; }; -// TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) -// TODO: onOpenChange SubMenu 展开/关闭的回调 -// TODO: onSelect 被选中时调用(点击子菜单标题不触发) +// TODO: 🎯 onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) inline +// TODO: 🎯 onOpenChange SubMenu 展开/关闭的回调 inline +// TODO: 🎯 onSelect 被选中时调用(点击子菜单标题不触发) inline +// TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) vertical +// TODO: onOpenChange SubMenu 展开/关闭的回调 vertical +// TODO: onSelect 被选中时调用(点击子菜单标题不触发) vertical +// TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) horizontal +// TODO: onOpenChange SubMenu 展开/关闭的回调 horizontal +// TODO: onSelect 被选中时调用(点击子菜单标题不触发) horizontal -// TODO: slots expandIcon 展开图标 +// TODO: slots expandIcon 展开图标 vertical +// TODO: slots expandIcon 展开图标 horizontal +// TODO: 🎯slots expandIcon 展开图标 inline export type KMenuItemProps = { /** @@ -114,7 +126,7 @@ export type SubMenuType = { */ icon?: string; /** - * TODO: 👀 菜单项标题 + * TODO: 菜单项标题 */ label?: string; /** @@ -160,7 +172,9 @@ export type SubMenuType = { // TODO: onTitleClick 点击子菜单标题 -// TODO: Items Slots slots label 分组标题 -// TODO: Items Slots slots icon 菜单图标 - - +// TODO: Items Slots slots label 分组标题 vertical +// TODO: Items Slots slots label 分组标题 horizontal +// TODO: 🎯Items Slots slots label 分组标题 inline +// TODO: Items Slots slots icon 菜单图标 vertical +// TODO: Items Slots slots icon 菜单图标 horizontal +// TODO: 🎯Items Slots slots icon 菜单图标 inline diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index e582f738..1705337b 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -17,8 +17,6 @@ export function transitionIn(node: HTMLElement) { duration: 300, tick: (t: number) => { if (t === 0) { - node.style.overflow = 'hidden'; - node.style.transition = 'height 0.3s'; node.style.height = '0'; } else if (t === 1) { node.style.removeProperty('height'); From a760a5a7d65ac2d31a6c97473ee4fa9e749aa2f0 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Wed, 17 Apr 2024 15:36:08 +0800 Subject: [PATCH 13/39] wip: KMenu component completes inline mode default submenu select item --- components/Menu/src/index.svelte | 9 ++++-- components/Menu/src/item.svelte | 55 +++++++++++++++++++++++++------- components/Menu/src/types.d.ts | 7 +++- components/Menu/src/utils.ts | 3 +- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 56727401..0d72dd0a 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -1,8 +1,8 @@ {#if show} -
        +
        {/if} diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index dedce8e5..f4ec44fd 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,12 +1,13 @@ {#each itemsList as it, index (it.uid)} - {#if it.type !== 'divider'} -
      • handleSelect(it, e)} - aria-hidden="true" - style:padding-left={`${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px`} - class={cnames(it)} - {...$$restProps} - {...attrs} - > - - - - {#if it.icon} - - {/if} - - {it.label} - + {#if ctxProps.mode === 'inline'} + {#if it.type !== 'divider'} +
      • handleSelect(it, e)} + aria-hidden="true" + style:padding-left={`${getIndent(it)}`} + class={cnames(it)} + {...$$restProps} + {...attrs} + > + + + + {#if it.icon} + + {/if} + + {it.label} + - {#if hasSub(it) && !isGroup(it)} - - - - {/if} - -
      • - - - handleSelectedRecursion(e, index)} - items={it.children} - level={getLevel(it, level) + 1}> - - + {#if hasSub(it) && !isGroup(it)} + + + + {/if} + + + + + handleSelectedRecursion(e, index)} + items={it.children} + level={getLevel(it, level) + 1} + > + + - - {#if item.icon} - - {/if} - - {item.label} - + + {#if item.icon} + + {/if} + + {item.label} + + {#if hasSub(item) && !isGroup(item)} + + + + {/if} + + + + + {:else} + + {/if} + {/if} + + {#if ctxProps.mode === 'vertical'} + + + {#if it.type !== 'divider'} +
      • handleSelect(it, e)} + aria-hidden="true" + style:padding-left={`${getIndent(it)}`} + class={cnames(it)} + {...$$restProps} + {...attrs} + > + + + + {#if it.icon} + + {/if} + + {it.label} + - {#if hasSub(item) && !isGroup(item)} - - + {#if hasSub(it) && !isGroup(it)} + + + + {/if} + +
      • + {#if isGroup(it)} + {#each (it.children || []) as child, childIndex (child.uid)} + handleSelectedRecursion(e, childIndex)} + items={[child]} + level={getLevel(child, level) + 1} + > + {/each} + + {/if} + {:else} + + {/if} +
        +
        + + handleSelectedRecursion(e, index)} + items={it.children} + level={getLevel(it, level) + 1} + > + + + + + {#if item.icon} + + {/if} + + {item.label} self + + {#if hasSub(item) && !isGroup(item)} + + + + {/if} - {/if} - - - - - {:else} - + + + +
        +
        {/if} {/each} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 80f00c07..e72e8e10 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -10,46 +10,45 @@ export type KMenuInstanceOption = { selectable?: boolean; subMenuCloseDelay?: number; subMenuOpenDelay?: number; - multiple?: boolean + multiple?: boolean; theme?: 'light' | 'dark'; triggerSubMenuAction?: 'hover' | 'click'; attrs?: Record; }; export type ClickEvtPa = { - item: SubMenuType - uid: string, - uidPath: string[] - e: MouseEvent -} + item: SubMenuType; + uid: string; + uidPath: string[]; + e: MouseEvent; +}; export type SelectEvtPa = { - item: SubMenuType - uid: string - uidPath: string[] - selectedUids: string[] - selectedItems: SubMenuType[] - selectedUidPaths: string[][] - e: MouseEvent -} + item: SubMenuType; + uid: string; + uidPath: string[]; + selectedUids: string[]; + selectedItems: SubMenuType[]; + selectedUidPaths: string[][]; + e: MouseEvent; +}; export type KMenuInstance = { __propHandleEvtMap: Array<(props: Record) => void>; __dynamicProps: KMenuInstanceOption; - __org_items?: SubMenuType[] - __selectedUids? : Set, - __openUids? : Set - __selectedItems? : Map - syncSelectedItems: ( - item: SubMenuType, - opType: 'set' | 'delete' = 'set') =>void + __org_items?: SubMenuType[]; + __selectedUids?: Set; + __openUids?: Set; + __selectedItems?: Map; + syncSelectedItems: (item: SubMenuType, opType: 'set' | 'delete' = 'set') => void; syncUids: ( uid: string | string[], type: 'open' | 'selected', - opType: 'add' | 'delete' = 'add') =>void - onOpenChange: (openUids: string[]) => void - onSelect: (param: SelectEvtPa) => void - onClick: (param: ClickEvtPa) => void + opType: 'add' | 'delete' = 'add' + ) => void; + onOpenChange: (openUids: string[]) => void; + onSelect: (param: SelectEvtPa) => void; + onClick: (param: ClickEvtPa) => void; }; export type KMenuProps = { @@ -116,7 +115,7 @@ export type KMenuProps = { * TODO: 是否允许多选 * @default 'true' */ - multiple?: boolean + multiple?: boolean; /** * TODO: SubMenu 展开/关闭的触发行为(非 inline 模式) * @default 'hover' @@ -188,7 +187,7 @@ export type SubMenuType = { /** * TODO: 设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) */ - title?: string + title?: string; /** * TODO: 👀 子菜单的菜单项 */ @@ -197,18 +196,19 @@ export type SubMenuType = { * TODO: 子菜单样式,mode="inline" 时无效 */ popupClassName?: string; + /** * @internal */ - selected?: boolean + selected?: boolean; /** * @internal */ - open?: boolean + open?: boolean; /** * @internal */ - selectedDeps?: Set + selectedDeps?: Set; [property: string]: any; }; @@ -220,3 +220,8 @@ export type SubMenuType = { // TODO: Items Slots slots icon 菜单图标 vertical // TODO: Items Slots slots icon 菜单图标 horizontal // TODO: 👀 Items Slots slots icon 菜单图标 inline + +// TODO: onSelect 选择子菜单时,再次选择被错误的取消 +// TODO: 非 inline 模式只允許一個子菜單 +// TODO: popover 对齐 +// TODO: 处理group diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index 4654c809..46eef5c6 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -1,10 +1,10 @@ -import type {KMenuInstance, KMenuInstanceOption, SubMenuType} from './types'; -import { isArray, isString } from "baiwusanyu-utils"; +import type { KMenuInstance, KMenuInstanceOption, SubMenuType } from './types'; +import { isArray, isString } from 'baiwusanyu-utils'; export const createKMenu = ( options: KMenuInstanceOption, onOpenChange: KMenuInstance['onOpenChange'], onSelect: KMenuInstance['onSelect'], - onClick: KMenuInstance['onClick'], + onClick: KMenuInstance['onClick'] ): KMenuInstance => { return { /** @@ -17,36 +17,30 @@ export const createKMenu = ( __openUids: new Set(options.openUids), __selectedUids: new Set(options.selectedUids), __selectedItems: new Map(), - syncUids( - uid: string | string[], - type: 'open' | 'selected', - opType: 'add' | 'delete' = 'add'){ - let uids = uid - if(isString(uid)){ - uids = [uid as string] + syncUids(uid: string | string[], type: 'open' | 'selected', opType: 'add' | 'delete' = 'add') { + let uids = uid; + if (isString(uid)) { + uids = [uid as string]; } - if(isArray(uids)){ - (uids as string[]).forEach(id => { - type === 'open' ? this.__openUids![opType](id) : this.__selectedUids![opType](id) + if (isArray(uids)) { + (uids as string[]).forEach((id) => { + type === 'open' ? this.__openUids![opType](id) : this.__selectedUids![opType](id); }); } }, - syncSelectedItems( - item: SubMenuType, - opType: 'set' | 'delete' = 'set' - ){ - const { uid } = item - if(opType === 'set'){ - this.__selectedItems?.set(uid!, item) + syncSelectedItems(item: SubMenuType, opType: 'set' | 'delete' = 'set') { + const { uid } = item; + if (opType === 'set') { + this.__selectedItems?.set(uid!, item); } - if(opType === 'delete'){ - this.__selectedItems?.delete(uid!) + if (opType === 'delete') { + this.__selectedItems?.delete(uid!); } }, onOpenChange, onSelect, - onClick, + onClick }; }; @@ -66,7 +60,7 @@ export function transitionIn(node: HTMLElement) { } export function transitionOut(node: HTMLElement) { - const orgHeight = node.scrollHeight + const orgHeight = node.scrollHeight; return { duration: 300, tick: (t: number) => { @@ -81,7 +75,7 @@ export function transitionOut(node: HTMLElement) { }; } -export function getUidPath(uid: string, list: SubMenuType[], path: string[] = []){ +export function getUidPath(uid: string, list: SubMenuType[], path: string[] = []) { // 遍历树结构数组中的每个节点 for (const node of list) { // 如果当前节点的 uid 与给定的 uid 匹配,返回当前路径 diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 640ed0af..509106fe 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -2,7 +2,6 @@ export const menuShortcuts: Record = { 'k-menu': 'bg-white text-ikun-tx-base p-0 m-0 box-border text-14px leading-0 list-none outline-none focus:outline-none k-menu-transition-w', - 'k-menu-item': 'box-border select-none', 'k-menu-item-icon-root': 'truncate fsc', 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0 min-w-14px', @@ -23,13 +22,19 @@ export const menuShortcuts: Record = { 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', - 'k-menu-item-vertical': '', + + 'k-menu-item-vertical': 'k-menu-item-inline', + 'k-menu-item-vertical-group': + 'k-menu-w k-menu-transition ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'rounded-8px ikun:50:text-black', + 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-style-position ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + 'rounded-8px active:(ikun:20:bg-ikun-main)', 'k-menu-item-inline-group': 'k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-style-position ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + 'rounded-8px ikun:50:text-black' }; From 456687209dacd9c7a4474171482b71a44b1400a9 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Sun, 21 Apr 2024 15:11:11 +0800 Subject: [PATCH 23/39] wip: KMenu component completes vertical mode group item render --- components/Menu/src/item.svelte | 48 +++++++++++++++++++++------------ components/Menu/src/types.d.ts | 2 +- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index f4ec44fd..bd1c24d8 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -32,7 +32,7 @@ } function initOpenSelectedStatus(list = itemsList) { - const res: SubMenuType[] = []; + let res: SubMenuType[] = []; let deps: string[] = []; list.forEach((value) => { const defaultSelected = menuCtx.__selectedUids?.has(value.uid || ''); @@ -44,7 +44,7 @@ deps.push(value.uid!); } - if (hasSub(value)) { + if (hasSub(value) && ctxProps.mode === 'inline') { const recRes = initOpenSelectedStatus(value.children!); value.children = recRes.children; if (!isGroup(value)) { @@ -60,8 +60,31 @@ deps = recRes.deps; } } + + if(hasSub(value) && ctxProps.mode === 'vertical'){ + const recRes = initOpenSelectedStatus(value.children!); + if (!isGroup(value)) { + value.children = recRes.children; + !value.selectedDeps && (value.selectedDeps = new Set()); + recRes.deps.forEach((d) => { + value.selectedDeps!.add(d); + }); + value.selected = !!value.selectedDeps.size; + if (value.selected) { + deps.push(value.uid!); + } + } else { + const { children } = value + value.children = [] + res.push({ ...value }); + res = res.concat(children!) + deps = recRes.deps; + return + } + } res.push({ ...value }); }); + return { children: res, deps @@ -97,6 +120,8 @@ | { detail: { selected: boolean; uid: string } }, index: number ) { + + debugger const { selected, uid } = e.detail; const it = itemsList[index]; if (!isGroup(it)) { @@ -120,6 +145,7 @@ } function setOpenAndSelectStatus(it: SubMenuType, list = itemsList) { + debugger return list.map((value) => { if (value.uid === it.uid && !isGroup(it)) { // set selected @@ -228,7 +254,7 @@ }; const popoverContentCls = clsx(`${prefixCls}-popover-content p-0 box-border`); - const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger !block`); + const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger`); $:getIndent = (it: SubMenuType) => { if(ctxProps.mode !== 'inline') { return `${ctxProps.inlineIndent}px` @@ -236,7 +262,6 @@ return `${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px` } - let groupChildIndex = 0 {#each itemsList as it, index (it.uid)} @@ -342,17 +367,6 @@ {/if} - {#if isGroup(it)} - {#each (it.children || []) as child, childIndex (child.uid)} - handleSelectedRecursion(e, childIndex)} - items={[child]} - level={getLevel(child, level) + 1} - > - {/each} - - {/if} {:else} {/if} @@ -361,7 +375,7 @@ {item.label} self - {#if hasSub(item) && !isGroup(item)} + {#if hasSub(item)} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index e72e8e10..4644908c 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -224,4 +224,4 @@ export type SubMenuType = { // TODO: onSelect 选择子菜单时,再次选择被错误的取消 // TODO: 非 inline 模式只允許一個子菜單 // TODO: popover 对齐 -// TODO: 处理group +// TODO: 处理group 样式 From 7633e4024760c20160eb3a1546a1817badb2ee8e Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Sun, 21 Apr 2024 17:16:11 +0800 Subject: [PATCH 24/39] wip: optimize the grouping style of KMenu component in vertical mode --- components/Menu/src/index.svelte | 13 ++++++++----- components/Menu/src/item.svelte | 26 +++++++++++++++++--------- components/Menu/src/types.d.ts | 15 +++++++++++++-- components/Popover/src/index.svelte | 4 +++- components/Popover/src/index.ts | 2 +- components/Popover/src/types.d.ts | 5 +++++ preset/src/shortcuts/src/menu.ts | 11 ++++++----- 7 files changed, 53 insertions(+), 23 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 2c101a18..b300a6ab 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -8,7 +8,7 @@ export let subMenuCloseDelay: KMenuProps['subMenuCloseDelay'] = 100; export let subMenuOpenDelay: KMenuProps['subMenuOpenDelay'] = 0; export let inlineIndent: KMenuProps['inlineIndent'] = 24; - export let expandIcon: KMenuProps['expandIcon'] = 'i-carbon-chevron-down'; + export let expandIcon: KMenuProps['expandIcon'] = ''; export let mode: KMenuProps['mode'] = 'vertical'; export let cls: KMenuProps['cls'] = undefined; export let attrs: KMenuProps['attrs'] = {}; @@ -17,6 +17,7 @@ export let show: KMenuProps['show'] = true; export let multiple: KMenuProps['multiple'] = true; export let selectable: KMenuProps['selectable'] = true; + export let ctxKey: KMenuProps['ctxKey'] = ''; const dispatch = createEventDispatcher(); function onOpenChange(openUids: string[]) { dispatch('openChange', openUids); @@ -44,14 +45,15 @@ selectedUids, multiple, selectable, - attrs + attrs, + ctxKey, }, onOpenChange, onSelect, onClick ); - if (!getContext(menuKey)) { - setContext(menuKey, menuInst); + if (!getContext(ctxKey || menuKey)) { + setContext(ctxKey || menuKey, menuInst); } $: { menuInst.__propHandleEvtMap.forEach((cb) => { @@ -66,7 +68,8 @@ multiple, selectedUids, selectable, - attrs + attrs, + ctxKey, }); }); } diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index bd1c24d8..756fe2f9 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -8,10 +8,12 @@ import { KMenu } from '@ikun-ui/menu'; import { getUidPath } from './utils'; import { KPopover } from '@ikun-ui/popover'; + import type { OffsetsFunction, OffsetsFnPa } from '@ikun-ui/popover'; export let items: KMenuItemProps['items'] = []; export let cls: KMenuItemProps['cls'] = undefined; export let attrs: KMenuItemProps['attrs'] = {}; export let level: KMenuItemProps['level'] = 1; + export let ctxKey: KMenuItemProps['ctxKey'] = ''; const dispatch = createEventDispatcher(); const hasSub = (it: SubMenuType) => !!(it.children && it.children.length); const isNotHorizontal = () => ctxProps.mode !== 'horizontal'; @@ -31,13 +33,14 @@ } } - function initOpenSelectedStatus(list = itemsList) { + function initOpenSelectedStatus(list = itemsList, inGroup: boolean = false) { let res: SubMenuType[] = []; let deps: string[] = []; list.forEach((value) => { const defaultSelected = menuCtx.__selectedUids?.has(value.uid || ''); const defaultOpen = menuCtx.__openUids?.has(value.uid || ''); value.selected = defaultSelected; + value.inGroup = inGroup menuCtx.syncSelectedItems(value, value.selected ? 'set' : 'delete'); value.open = defaultOpen; if (defaultSelected) { @@ -62,7 +65,7 @@ } if(hasSub(value) && ctxProps.mode === 'vertical'){ - const recRes = initOpenSelectedStatus(value.children!); + const recRes = initOpenSelectedStatus(value.children!, isGroup(value)); if (!isGroup(value)) { value.children = recRes.children; !value.selectedDeps && (value.selectedDeps = new Set()); @@ -121,7 +124,6 @@ index: number ) { - debugger const { selected, uid } = e.detail; const it = itemsList[index]; if (!isGroup(it)) { @@ -145,7 +147,6 @@ } function setOpenAndSelectStatus(it: SubMenuType, list = itemsList) { - debugger return list.map((value) => { if (value.uid === it.uid && !isGroup(it)) { // set selected @@ -231,7 +232,7 @@ const iconCls = clsx(`${prefixCls}-icon`); const iconRootCls = clsx(`${prefixCls}-icon-root`); - const expendIconCls = (it: SubMenuType) => { + $: expendIconCls = (it: SubMenuType) => { if (ctxProps.mode === 'vertical') { return resolvedExpandIcon; } @@ -254,14 +255,18 @@ }; const popoverContentCls = clsx(`${prefixCls}-popover-content p-0 box-border`); - const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger`); + const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger-v`); $:getIndent = (it: SubMenuType) => { if(ctxProps.mode !== 'inline') { - return `${ctxProps.inlineIndent}px` + return `${it.inGroup ? (ctxProps.inlineIndent || 24) * 2 : ctxProps.inlineIndent}px` } return `${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px` } + const setPopoverOffset: OffsetsFunction = ({popper, placement, reference}: OffsetsFnPa) => { + return [popper.height / 2 - reference.height / 2, 4] + } + {#each itemsList as it, index (it.uid)} @@ -295,6 +300,7 @@ @@ -333,8 +339,9 @@ {#if ctxProps.mode === 'vertical'} @@ -391,7 +399,7 @@ {/if} - {item.label} self + {item.label} {#if hasSub(item)} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 4644908c..e6cd5a73 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -14,6 +14,7 @@ export type KMenuInstanceOption = { theme?: 'light' | 'dark'; triggerSubMenuAction?: 'hover' | 'click'; attrs?: Record; + ctxKey?: string }; export type ClickEvtPa = { @@ -52,6 +53,10 @@ export type KMenuInstance = { }; export type KMenuProps = { + /** + * TODO: 👀 上下文 key + */ + ctxKey?: string /** * TODO: 👀 展开图标 * @default 'i-carbon-chevron-down' @@ -148,6 +153,10 @@ export type KMenuItemProps = { * @internal */ level: number; + /** + * TODO: 👀 上下文 key + */ + ctxKey?: string items: SubMenuType[]; cls: ClassValue; attrs: Record; @@ -196,7 +205,10 @@ export type SubMenuType = { * TODO: 子菜单样式,mode="inline" 时无效 */ popupClassName?: string; - + /** + * @internal + */ + inGroup?: boolean; /** * @internal */ @@ -224,4 +236,3 @@ export type SubMenuType = { // TODO: onSelect 选择子菜单时,再次选择被错误的取消 // TODO: 非 inline 模式只允許一個子菜單 // TODO: popover 对齐 -// TODO: 处理group 样式 diff --git a/components/Popover/src/index.svelte b/components/Popover/src/index.svelte index 9b078e75..85407abf 100644 --- a/components/Popover/src/index.svelte +++ b/components/Popover/src/index.svelte @@ -21,6 +21,7 @@ * @internal */ export let width: KPopoverProps['width'] = 'fit-content'; + export let offset: KPopoverProps['offset'] = [0, 8]; $: curPlacement = placement; let arrowRef: null | HTMLElement = null; const dispatch = createEventDispatcher(); @@ -31,7 +32,8 @@ { name: 'offset', options: { - offset: [0, 8] + // TODO: feature props + offset, } }, { diff --git a/components/Popover/src/index.ts b/components/Popover/src/index.ts index b3a835ca..dd606c24 100644 --- a/components/Popover/src/index.ts +++ b/components/Popover/src/index.ts @@ -5,4 +5,4 @@ export default Popover; export { Popover as KPopover }; -export type { KPopoverProps } from './types'; +export type { KPopoverProps, OffsetsFunction, OffsetsFnPa } from './types'; diff --git a/components/Popover/src/types.d.ts b/components/Popover/src/types.d.ts index 47c1af5b..7a9897f3 100644 --- a/components/Popover/src/types.d.ts +++ b/components/Popover/src/types.d.ts @@ -8,6 +8,7 @@ export type KPopoverProps = { trigger: IKunTrigger; disabled: boolean; arrow: boolean; + offset: OffsetsFunction | [?number, ?number]; cls: ClassValue; clsTrigger: ClassValue; mouseEnterDelay: number; @@ -15,3 +16,7 @@ export type KPopoverProps = { width: string | null | undefined; attrs: Record; }; + +export type OffsetsFunction = (data: OffsetsFnPa) => [?number, ?number]; + +export type OffsetsFnPa = { popper: DOMRect, reference: DOMRect, placement: IKunPlacement } diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 509106fe..e4a8a809 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -7,7 +7,7 @@ export const menuShortcuts: Record = { 'k-menu-item-icon': 'inline-flex text-inherit items-center leading-0 min-w-14px', 'k-menu-title-content': 'truncate box-border k-menu-transition-c select-none', 'k-menu-title-content-i': 'm-is-6px m-ie-6px k-menu-transition-o opacity-[1] truncate', - 'k-menu-item-divider': 'my-0', + 'k-menu-item-divider': 'my-0 w-full', 'k-menu-sub': 'border-none bg-transparent', 'k-menu-sub-bg': 'ikun:2:bg-black', @@ -23,18 +23,19 @@ export const menuShortcuts: Record = { 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', - 'k-menu-item-vertical': 'k-menu-item-inline', + 'k-menu-item-popover-trigger-v': 'box-border my-4px', + 'k-menu-item-vertical': 'k-menu-item-inline my-0', 'k-menu-item-vertical-group': 'k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px ' + 'rounded-8px ikun:50:text-black', 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px my-4px ' + 'rounded-8px active:(ikun:20:bg-ikun-main)', 'k-menu-item-inline-group': 'k-menu-w k-menu-transition ' + - 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px m-bs-4px m-be-4px ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px my-4px ' + 'rounded-8px ikun:50:text-black' }; From 06305bfbb14201c9d2224ff99a1d21a2e58fc112 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Sun, 21 Apr 2024 17:50:48 +0800 Subject: [PATCH 25/39] wip: temp commit --- components/Menu/src/item.svelte | 19 +++++++------------ components/Menu/src/types.d.ts | 1 - 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 756fe2f9..48d5698c 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -5,7 +5,7 @@ import { getPrefixCls, menuKey } from '@ikun-ui/utils'; import { clsx } from 'clsx'; import { KDivider } from '@ikun-ui/divider'; - import { KMenu } from '@ikun-ui/menu'; + import KMenu from './index'; import { getUidPath } from './utils'; import { KPopover } from '@ikun-ui/popover'; import type { OffsetsFunction, OffsetsFnPa } from '@ikun-ui/popover'; @@ -96,21 +96,15 @@ const menuCtx = getContext(menuKey) as KMenuInstance; let ctxProps: KMenuInstanceOption = {}; - let resolvedExpandIcon = 'i-carbon-chevron-down'; - function setExpandIcon() { - resolvedExpandIcon = - ctxProps.mode === 'vertical' ? `${ctxProps.expandIcon} -rotate-90` : ctxProps.expandIcon!; - } + function updatedCtxProps(props: Record) { ctxProps = { ...props }; menuCtx.syncUids(ctxProps.openUids || [], 'open'); menuCtx.syncUids(ctxProps.selectedUids || [], 'selected'); itemsList = initOpenSelectedStatus().children; - setExpandIcon(); } if (menuCtx) { ctxProps = { ...menuCtx.__dynamicProps }; - setExpandIcon(); menuCtx.__propHandleEvtMap.push(updatedCtxProps); if (level === 1) { menuCtx.__org_items = items; @@ -233,12 +227,13 @@ const iconRootCls = clsx(`${prefixCls}-icon-root`); $: expendIconCls = (it: SubMenuType) => { + const icon = (ctxProps.expandIcon || 'i-carbon-chevron-down '); if (ctxProps.mode === 'vertical') { - return resolvedExpandIcon; + return `${icon} -rotate-90` } return it.open - ? `${resolvedExpandIcon} rotate-180 k-icon-transition` - : `${resolvedExpandIcon} k-icon-transition`; + ? `${icon} rotate-180 k-icon-transition` + : `${icon} k-icon-transition`; }; const titleContentCls = (hasIcon: boolean) => { @@ -263,7 +258,7 @@ return `${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px` } - const setPopoverOffset: OffsetsFunction = ({popper, placement, reference}: OffsetsFnPa) => { + const setPopoverOffset: OffsetsFunction = ({popper, reference}: OffsetsFnPa) => { return [popper.height / 2 - reference.height / 2, 4] } diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index e6cd5a73..2c216bf3 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -235,4 +235,3 @@ export type SubMenuType = { // TODO: onSelect 选择子菜单时,再次选择被错误的取消 // TODO: 非 inline 模式只允許一個子菜單 -// TODO: popover 对齐 From b0b0c1b287745a68cc4b7cd2b00c842ddf361625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Sun, 21 Apr 2024 22:16:09 +0800 Subject: [PATCH 26/39] wip: fix gorup item render error --- components/Menu/src/item.svelte | 11 +++++++---- components/Menu/src/types.d.ts | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 48d5698c..f933bd9e 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -9,6 +9,7 @@ import { getUidPath } from './utils'; import { KPopover } from '@ikun-ui/popover'; import type { OffsetsFunction, OffsetsFnPa } from '@ikun-ui/popover'; + import {jsonClone} from "baiwusanyu-utils"; export let items: KMenuItemProps['items'] = []; export let cls: KMenuItemProps['cls'] = undefined; export let attrs: KMenuItemProps['attrs'] = {}; @@ -20,14 +21,14 @@ const isGroup = (it: SubMenuType) => it.type === 'group'; const getLevel = (it: SubMenuType, lv: number) => { if (isGroup(it)) { - return lv - 1; + return Math.max(lv - 1, 1); } return lv; }; - let itemsList = items; + let itemsList = level === 1 ? jsonClone(items) : items; $: { - itemsList = items; + itemsList = level === 1 ? jsonClone(items) : items; if (level === 1) { itemsList = initOpenSelectedStatus().children; } @@ -94,7 +95,7 @@ }; } - const menuCtx = getContext(menuKey) as KMenuInstance; + const menuCtx = getContext(ctxKey || menuKey) as KMenuInstance; let ctxProps: KMenuInstanceOption = {}; function updatedCtxProps(props: Record) { @@ -301,6 +302,7 @@ > handleSelectedRecursion(e, index)} items={it.children} level={getLevel(it, level) + 1} @@ -382,6 +384,7 @@ > handleSelectedRecursion(e, index)} items={it.children} level={getLevel(it, level) + 1} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 2c216bf3..4cce9315 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -95,7 +95,7 @@ export type KMenuProps = { */ selectedUids?: string[]; /** - * TODO: 👀是否允许选中(为 false, 点击不高亮,不触发 select事件) inline + * TODO: 👀 是否允许选中(为 false, 点击不高亮,不触发 select事件) inline * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) vertical * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) horizontal * @default false @@ -122,7 +122,7 @@ export type KMenuProps = { */ multiple?: boolean; /** - * TODO: SubMenu 展开/关闭的触发行为(非 inline 模式) + * TODO: 👀 SubMenu 展开/关闭的触发行为(非 inline 模式) * @default 'hover' */ triggerSubMenuAction?: 'hover' | 'click'; @@ -194,7 +194,7 @@ export type SubMenuType = { */ theme?: 'light' | 'dark'; /** - * TODO: 设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) + * TODO: 🎯设置收缩时展示的悬浮标题(无子菜单情况下生效,不传时默认为 label) */ title?: string; /** @@ -234,4 +234,4 @@ export type SubMenuType = { // TODO: 👀 Items Slots slots icon 菜单图标 inline // TODO: onSelect 选择子菜单时,再次选择被错误的取消 -// TODO: 非 inline 模式只允許一個子菜單 +// TODO: 🎯 测试非inline 模式下 ‘👀’ 的功能 From 72ad9fb14ef56f5637e0bf50152016bb7d2aa104 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Mon, 22 Apr 2024 11:05:19 +0800 Subject: [PATCH 27/39] wip: KMenu component completes vertical mode subMenuCloseDelay and subMenuOpneDelay props --- components/Menu/src/item.svelte | 2 ++ components/Menu/src/types.d.ts | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index f933bd9e..a54c5af9 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -339,6 +339,8 @@ width="100%" placement="right" offset={setPopoverOffset} + mouseEnterDelay={ctxProps.subMenuOpenDelay} + mouseLeaveDelay={ctxProps.subMenuCloseDelay} trigger={ctxProps.triggerSubMenuAction} cls={popoverContentCls} clsTrigger={popoverTriggerCls} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 4cce9315..af84bc88 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -82,32 +82,32 @@ export type KMenuProps = { mode?: `vertical` | `horizontal` | `inline`; /** * TODO: 👀 当前展开的 SubMenu 菜单项 key 数组 inline - * TODO: 当前展开的 SubMenu 菜单项 key 数组 vertical + * TODO: 🎯 当前展开的 SubMenu 菜单项 key 数组 vertical * TODO: 当前展开的 SubMenu 菜单项 key 数组 horizontal * @default `[]` */ openUids?: string[]; /** * TODO: 👀 当前选中的菜单项 key 数组(子菜单只高亮,不展开) inline - * TODO: 当前选中的菜单项 key 数组(子菜单只高亮,不展开) vertical + * TODO: 👀 当前选中的菜单项 key 数组(子菜单只高亮,不展开) vertical * TODO: 当前选中的菜单项 key 数组(子菜单只高亮,不展开) horizontal * @default `[]` */ selectedUids?: string[]; /** * TODO: 👀 是否允许选中(为 false, 点击不高亮,不触发 select事件) inline - * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) vertical + * TODO: 👀 是否允许选中(为 false, 点击不高亮,不触发 select事件) vertical * TODO: 是否允许选中(为 false, 点击不高亮,不触发 select事件) horizontal * @default false */ selectable?: boolean; /** - * TODO: 用户鼠标离开子菜单后关闭延时,单位:毫秒(非 inline 模式, hover触发) + * TODO: 👀 用户鼠标离开子菜单后关闭延时,单位:毫秒(非 inline 模式, hover触发) * @default 100ms */ subMenuCloseDelay?: number; /** - * TODO: 用户鼠标进入子菜单后开启延时,单位:毫秒(非 inline 模式, hover触发) + * TODO: 👀 用户鼠标进入子菜单后开启延时,单位:毫秒(非 inline 模式, hover触发) * @default 0 */ subMenuOpenDelay?: number; @@ -137,14 +137,16 @@ export type KMenuProps = { // TODO: 👀 onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) inline // TODO: 👀 onOpenChange SubMenu 展开/关闭的回调 inline // TODO: 👀 onSelect 被选中时调用(点击子菜单标题不触发) inline -// TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) vertical -// TODO: onOpenChange SubMenu 展开/关闭的回调 vertical -// TODO: onSelect 被选中时调用(点击子菜单标题不触发) vertical + +// TODO: 👀 onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) vertical +// TODO: 👀 onOpenChange SubMenu 展开/关闭的回调 vertical +// TODO: 👀 onSelect 被选中时调用(点击子菜单标题不触发) vertical + // TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) horizontal // TODO: onOpenChange SubMenu 展开/关闭的回调 horizontal // TODO: onSelect 被选中时调用(点击子菜单标题不触发) horizontal -// TODO: slots expandIcon 展开图标 vertical +// TODO: 👀 slots expandIcon 展开图标 vertical // TODO: slots expandIcon 展开图标 horizontal // TODO: 👀 slots expandIcon 展开图标 inline @@ -226,12 +228,12 @@ export type SubMenuType = { // TODO: onTitleClick 点击子菜单标题 -// TODO: Items Slots slots label 分组标题 vertical +// TODO: 🎯Items Slots slots label 分组标题 vertical // TODO: Items Slots slots label 分组标题 horizontal // TODO: 🎯Items Slots slots label 分组标题 inline -// TODO: Items Slots slots icon 菜单图标 vertical +// TODO: 👀 Items Slots slots icon 菜单图标 vertical // TODO: Items Slots slots icon 菜单图标 horizontal // TODO: 👀 Items Slots slots icon 菜单图标 inline -// TODO: onSelect 选择子菜单时,再次选择被错误的取消 -// TODO: 🎯 测试非inline 模式下 ‘👀’ 的功能 +// TODO: 🎯 onSelect 选择子菜单时,选择和取消的预期行为是什么 +// TODO: 🎯 onOpenChange 选择和取消的预期行为是什么 From 81854d48702bc177090abe9b44dceb5f0d8c8bcb Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Mon, 22 Apr 2024 13:39:08 +0800 Subject: [PATCH 28/39] wip: KMenu component completes vertical and inline mode onDeSelect event --- components/Menu/src/index.svelte | 11 ++++-- components/Menu/src/item.svelte | 60 +++++++++++++++----------------- components/Menu/src/types.d.ts | 13 +++---- components/Menu/src/utils.ts | 6 ++-- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index b300a6ab..4456d399 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -30,6 +30,10 @@ function onClick(data: ClickEvtPa) { dispatch('click', data); } + + function onDeSelect(data: SelectEvtPa) { + dispatch('deSelect', data); + } /** * @internal */ @@ -46,11 +50,12 @@ multiple, selectable, attrs, - ctxKey, + ctxKey }, onOpenChange, onSelect, - onClick + onClick, + onDeSelect ); if (!getContext(ctxKey || menuKey)) { setContext(ctxKey || menuKey, menuInst); @@ -69,7 +74,7 @@ selectedUids, selectable, attrs, - ctxKey, + ctxKey }); }); } diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index a54c5af9..6a2f30ca 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -8,8 +8,8 @@ import KMenu from './index'; import { getUidPath } from './utils'; import { KPopover } from '@ikun-ui/popover'; - import type { OffsetsFunction, OffsetsFnPa } from '@ikun-ui/popover'; - import {jsonClone} from "baiwusanyu-utils"; + import type { OffsetsFunction, OffsetsFnPa } from '@ikun-ui/popover'; + import { jsonClone } from 'baiwusanyu-utils'; export let items: KMenuItemProps['items'] = []; export let cls: KMenuItemProps['cls'] = undefined; export let attrs: KMenuItemProps['attrs'] = {}; @@ -41,7 +41,7 @@ const defaultSelected = menuCtx.__selectedUids?.has(value.uid || ''); const defaultOpen = menuCtx.__openUids?.has(value.uid || ''); value.selected = defaultSelected; - value.inGroup = inGroup + value.inGroup = inGroup; menuCtx.syncSelectedItems(value, value.selected ? 'set' : 'delete'); value.open = defaultOpen; if (defaultSelected) { @@ -65,7 +65,7 @@ } } - if(hasSub(value) && ctxProps.mode === 'vertical'){ + if (hasSub(value) && ctxProps.mode === 'vertical') { const recRes = initOpenSelectedStatus(value.children!, isGroup(value)); if (!isGroup(value)) { value.children = recRes.children; @@ -78,12 +78,12 @@ deps.push(value.uid!); } } else { - const { children } = value - value.children = [] + const { children } = value; + value.children = []; res.push({ ...value }); - res = res.concat(children!) + res = res.concat(children!); deps = recRes.deps; - return + return; } } res.push({ ...value }); @@ -118,7 +118,6 @@ | { detail: { selected: boolean; uid: string } }, index: number ) { - const { selected, uid } = e.detail; const it = itemsList[index]; if (!isGroup(it)) { @@ -191,7 +190,7 @@ if (!hasSub(it) && !isGroup(it) && ctxProps.selectable) { menuCtx.syncUids(it.uid!, 'selected', it.selected ? 'add' : 'delete'); menuCtx.syncSelectedItems(it, it.selected ? 'set' : 'delete'); - menuCtx.onSelect({ + const params = { item: it, uid: it.uid!, uidPath, @@ -201,7 +200,12 @@ (uid) => getUidPath(uid, menuCtx.__org_items!) || [] ), e - }); + }; + if (it.selected) { + menuCtx.onSelect(params); + } else { + menuCtx.onDeSelect(params); + } } } } @@ -228,13 +232,11 @@ const iconRootCls = clsx(`${prefixCls}-icon-root`); $: expendIconCls = (it: SubMenuType) => { - const icon = (ctxProps.expandIcon || 'i-carbon-chevron-down '); + const icon = ctxProps.expandIcon || 'i-carbon-chevron-down '; if (ctxProps.mode === 'vertical') { - return `${icon} -rotate-90` + return `${icon} -rotate-90`; } - return it.open - ? `${icon} rotate-180 k-icon-transition` - : `${icon} k-icon-transition`; + return it.open ? `${icon} rotate-180 k-icon-transition` : `${icon} k-icon-transition`; }; const titleContentCls = (hasIcon: boolean) => { @@ -252,17 +254,16 @@ const popoverContentCls = clsx(`${prefixCls}-popover-content p-0 box-border`); const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger-v`); - $:getIndent = (it: SubMenuType) => { - if(ctxProps.mode !== 'inline') { - return `${it.inGroup ? (ctxProps.inlineIndent || 24) * 2 : ctxProps.inlineIndent}px` + $: getIndent = (it: SubMenuType) => { + if (ctxProps.mode !== 'inline') { + return `${it.inGroup ? (ctxProps.inlineIndent || 24) * 2 : ctxProps.inlineIndent}px`; } - return `${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px` - } - - const setPopoverOffset: OffsetsFunction = ({popper, reference}: OffsetsFnPa) => { - return [popper.height / 2 - reference.height / 2, 4] - } + return `${(ctxProps.inlineIndent || 24) * getLevel(it, level)}px`; + }; + const setPopoverOffset: OffsetsFunction = ({ popper, reference }: OffsetsFnPa) => { + return [popper.height / 2 - reference.height / 2, 4]; + }; {#each itemsList as it, index (it.uid)} @@ -344,7 +345,7 @@ trigger={ctxProps.triggerSubMenuAction} cls={popoverContentCls} clsTrigger={popoverTriggerCls} - disabled={!((hasSub(it)) || isGroup(it))} + disabled={!(hasSub(it) || isGroup(it))} > {#if it.type !== 'divider'} @@ -378,12 +379,7 @@ {/if}
        - + ; - ctxKey?: string + ctxKey?: string; }; export type ClickEvtPa = { @@ -49,6 +49,7 @@ export type KMenuInstance = { ) => void; onOpenChange: (openUids: string[]) => void; onSelect: (param: SelectEvtPa) => void; + onDeSelect: (param: SelectEvtPa) => void; onClick: (param: ClickEvtPa) => void; }; @@ -56,7 +57,7 @@ export type KMenuProps = { /** * TODO: 👀 上下文 key */ - ctxKey?: string + ctxKey?: string; /** * TODO: 👀 展开图标 * @default 'i-carbon-chevron-down' @@ -137,14 +138,17 @@ export type KMenuProps = { // TODO: 👀 onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) inline // TODO: 👀 onOpenChange SubMenu 展开/关闭的回调 inline // TODO: 👀 onSelect 被选中时调用(点击子菜单标题不触发) inline +// TODO: 👀 onDeSelect 被选中时调用(点击子菜单标题不触发) inline // TODO: 👀 onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) vertical // TODO: 👀 onOpenChange SubMenu 展开/关闭的回调 vertical // TODO: 👀 onSelect 被选中时调用(点击子菜单标题不触发) vertical +// TODO: 👀 onDeSelect 被选中时调用(点击子菜单标题不触发) inline // TODO: onClick 点击 MenuItem 调用此函数(点击子菜单标题不触发) horizontal // TODO: onOpenChange SubMenu 展开/关闭的回调 horizontal // TODO: onSelect 被选中时调用(点击子菜单标题不触发) horizontal +// TODO: onDeSelect 被选中时调用(点击子菜单标题不触发) inline // TODO: 👀 slots expandIcon 展开图标 vertical // TODO: slots expandIcon 展开图标 horizontal @@ -158,7 +162,7 @@ export type KMenuItemProps = { /** * TODO: 👀 上下文 key */ - ctxKey?: string + ctxKey?: string; items: SubMenuType[]; cls: ClassValue; attrs: Record; @@ -234,6 +238,3 @@ export type SubMenuType = { // TODO: 👀 Items Slots slots icon 菜单图标 vertical // TODO: Items Slots slots icon 菜单图标 horizontal // TODO: 👀 Items Slots slots icon 菜单图标 inline - -// TODO: 🎯 onSelect 选择子菜单时,选择和取消的预期行为是什么 -// TODO: 🎯 onOpenChange 选择和取消的预期行为是什么 diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index 46eef5c6..892c8d5d 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -4,7 +4,8 @@ export const createKMenu = ( options: KMenuInstanceOption, onOpenChange: KMenuInstance['onOpenChange'], onSelect: KMenuInstance['onSelect'], - onClick: KMenuInstance['onClick'] + onClick: KMenuInstance['onClick'], + onDeSelect: KMenuInstance['onDeSelect'] ): KMenuInstance => { return { /** @@ -40,7 +41,8 @@ export const createKMenu = ( }, onOpenChange, onSelect, - onClick + onClick, + onDeSelect }; }; From c5f8bcc67547843c776a6f124fe8adda07317421 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Mon, 22 Apr 2024 17:47:37 +0800 Subject: [PATCH 29/39] wip: KMenu component vertical mode openUids props temp commit --- components/Menu/src/item.svelte | 41 ++++++++++++++++++++++++++++- components/Menu/src/types.d.ts | 4 +++ components/Popover/src/index.svelte | 21 ++++++++++----- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 6a2f30ca..d0077bea 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,5 +1,5 @@ {#each itemsList as it, index (it.uid)} @@ -461,4 +489,85 @@
        {/if} + + {#if ctxProps.mode === 'horizontal'} + + + {#if it.type !== 'divider'} +
      • handleSelect(it, e)} + aria-hidden="true" + style:padding-left={`${getIndent(it)}`} + class={cnames(it)} + {...$$restProps} + {...attrs} + > + + + + {#if it.icon} + + {/if} + + {it.label} + + + {#if hasSub(it) && !isGroup(it) && level !== 1} + + + + {/if} + +
      • + {:else} + + {/if} +
        +
        + + handleSelectedRecursion(e, index)} + items={it.children} + level={getLevel(it, level) + 1} + > + + + + + {#if item.icon} + + {/if} + + {item.label} + + {#if hasSub(item)} + + + + {/if} + + + + +
        +
        + {/if} {/each} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 96f1f89c..16afd36e 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -60,6 +60,7 @@ export type KMenuProps = { ctxKey?: string; /** * TODO: 👀 展开图标 + * TODO: 展开图标 horizontal(more menu 展示) * @default 'i-carbon-chevron-down' */ expandIcon?: string; @@ -233,8 +234,11 @@ export type SubMenuType = { // TODO: onTitleClick 点击子菜单标题 // TODO: 🎯Items Slots slots label 分组标题 vertical -// TODO: Items Slots slots label 分组标题 horizontal +// TODO: 🎯Items Slots slots label 分组标题 horizontal // TODO: 🎯Items Slots slots label 分组标题 inline // TODO: 👀 Items Slots slots icon 菜单图标 vertical // TODO: Items Slots slots icon 菜单图标 horizontal // TODO: 👀 Items Slots slots icon 菜单图标 inline + +// 🎯 TODO horizontal 缩略适配 +// 🎯 TODO 所有 👀 功能 diff --git a/preset/src/shortcuts/src/common.ts b/preset/src/shortcuts/src/common.ts index 44f00c14..f8dc7fe4 100644 --- a/preset/src/shortcuts/src/common.ts +++ b/preset/src/shortcuts/src/common.ts @@ -40,6 +40,7 @@ export const commonShortcuts: UserShortcuts = { 'n-bdl-1': 'border-l-0 border-t-1 border-b-1 border-r-1', 'bd-2': 'border-t-2 border-l-2 border-b-2 border-r-2', 'bdl-2': 'border-l-2 border-t-0 border-b-0 border-r-0', + 'bdb-2': 'border-l-0 border-t-0 border-b-2 border-r-0', 'bdtr-2': 'border-l-0 border-t-2 border-b-0 border-r-2', 'bd-3': 'border-t-3 border-l-3 border-b-3 border-r-3' }; diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index e4a8a809..2cc9ddcb 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -12,24 +12,40 @@ export const menuShortcuts: Record = { 'k-menu-sub': 'border-none bg-transparent', 'k-menu-sub-bg': 'ikun:2:bg-black', - 'k-menu-horizontal': '', - 'k-menu-item-horizontal': '', - 'k-menu-item-selected': 'ikun:20:bg-ikun-main text-ikun-main hover:(ikun:20:bg-ikun-main)', - 'k-menu-item-selected-ih': 'text-ikun-main', - 'k-menu-item-hover-ih': 'hover:(ikun:6:bg-ikun-black)', - 'k-menu-item-vh-child': 'justify-between', + 'k-menu-item-selected-group': 'text-ikun-main', + 'k-menu-item-hover': 'hover:(ikun:6:bg-ikun-black)', - 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', - 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-item-selected-after': + 'after:(content-empty pa bottom-0 bdb-2 border-solid b-b-ikun-main w-full left-0 animate-ikun-scale)', + 'k-menu-item-selected-h': 'text-ikun-main k-menu-item-selected-after', + 'k-menu-item-selected-group-h': 'text-ikun-main k-menu-item-selected-after', + 'k-menu-item-hover-h': 'hover:(k-menu-item-selected-after)', - 'k-menu-item-popover-trigger-v': 'box-border my-4px', + 'k-menu-item-child': 'justify-between', + + 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-item-popover-trigger-vertical': 'box-border my-4px', 'k-menu-item-vertical': 'k-menu-item-inline my-0', 'k-menu-item-vertical-group': 'k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px ' + 'rounded-8px ikun:50:text-black', + 'k-menu-horizontal': 'bdb-1 b-e-solid border-ikun-bd-base flex [&.k-menu-sub-horizontal]:block', + 'k-menu-item-popover-trigger-horizontal': 'box-border my-4px', + 'k-menu-item-popover-content': 'p-0 box-border', + 'k-menu-item-horizontal': + 'cursor-pointer k-menu-w k-menu-transition ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px my-4px ' + + 'rounded-8px my-0', + 'k-menu-item-horizontal-not-top': 'k-menu-item-horizontal active:(ikun:20:bg-ikun-main)', + 'k-menu-item-horizontal-group': + 'k-menu-w k-menu-transition ' + + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px ' + + 'rounded-8px ikun:50:text-black', + + 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px my-4px ' + diff --git a/preset/src/theme/index.ts b/preset/src/theme/index.ts index cffdbd44..fea255cb 100644 --- a/preset/src/theme/index.ts +++ b/preset/src/theme/index.ts @@ -123,6 +123,16 @@ const getAnimation = (themeColor: string) => { 'ikun-skeleton-loading': `{ 0% { background-position: 100% 50%;} 100% { background-position: 0 50%; } + }`, + 'ikun-scale': `{ + from { + transform: scale(0); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } }` }, durations: { @@ -134,7 +144,8 @@ const getAnimation = (themeColor: string) => { 'ikun-checking-main': '.3s', 'ikun-checking': '.3s', 'ikun-switching': '.3s', - 'ikun-skeleton-loading': '1.4s' + 'ikun-skeleton-loading': '1.4s', + 'ikun-scale': '.3s' }, timingFns: { 'ikun-clicking--success': 'linear', @@ -146,7 +157,8 @@ const getAnimation = (themeColor: string) => { 'ikun-clicking': 'linear', 'ikun-checking': 'linear', 'ikun-switching': 'linear', - 'ikun-skeleton-loading': 'ease' + 'ikun-skeleton-loading': 'ease', + 'ikun-scale': 'forwards' }, counts: { 'ikun-skeleton-loading': 'infinite' From a1a40a42f731c2159c6e45062ceb8e693770c969 Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Tue, 23 Apr 2024 18:00:45 +0800 Subject: [PATCH 32/39] wip: optimization the styling of the KMenu component in horizontal mode --- components/Menu/src/index.svelte | 1 - components/Menu/src/item.svelte | 18 +++++++++++++----- components/Menu/src/types.d.ts | 8 ++++---- preset/src/shortcuts/src/menu.ts | 10 ++++++---- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 4456d399..040d1bf0 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -87,7 +87,6 @@
          { return clsx(`${menuPrefixCls}-sub`, `${menuPrefixCls}-sub-${ctxProps.mode}`, { [`${menuPrefixCls}-sub-bg`]: !isGroup @@ -316,7 +319,12 @@ }; const popoverContentCls = clsx(`${prefixCls}-popover-content`); - const popoverTriggerCls = clsx(`${prefixCls}-popover-trigger-${ctxProps.mode}`); + const popoverTriggerCls = (isDivider: boolean = false) => { + return clsx({ + [`${prefixCls}-popover-trigger-${ctxProps.mode}`]: !isDivider && isNotHorizontalTop(), + [`${prefixCls}-popover-trigger-${ctxProps.mode}-divider`]: isDivider && !isNotHorizontalTop() + }); + }; $: getIndent = (it: SubMenuType) => { if (ctxProps.mode === 'horizontal' && level === 1) return '16px'; if (ctxProps.mode !== 'inline') { @@ -422,7 +430,7 @@ mouseLeaveDelay={ctxProps.subMenuCloseDelay} trigger={ctxProps.triggerSubMenuAction} cls={popoverContentCls} - clsTrigger={popoverTriggerCls} + clsTrigger={popoverTriggerCls(false)} disabled={!(hasSub(it) || isGroup(it))} > @@ -503,7 +511,7 @@ mouseLeaveDelay={ctxProps.subMenuCloseDelay} trigger={ctxProps.triggerSubMenuAction} cls={popoverContentCls} - clsTrigger={popoverTriggerCls} + clsTrigger={popoverTriggerCls(it.type === 'divider')} disabled={!(hasSub(it) || isGroup(it))} > @@ -534,7 +542,7 @@ {:else} - + {/if}
          diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index 16afd36e..f5ec36f4 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -76,8 +76,8 @@ export type KMenuProps = { inlineCollapsed?: boolean; /** * TODO: 👀 菜单类型,现在支持垂直、水平、和内嵌模式三种 inline - * TODO: 🎯 菜单类型,现在支持垂直、水平、和内嵌模式三种 vertical - * TODO: 菜单类型,现在支持垂直、水平、和内嵌模式三种 horizontal + * TODO: 👀 菜单类型,现在支持垂直、水平、和内嵌模式三种 vertical + * TODO: 🎯 菜单类型,现在支持垂直、水平、和内嵌模式三种 horizontal * `vertical` 和 `inline` 的区别在于 `vertical` 子菜单以 popover 形式出现 * @default `vertical` */ @@ -237,8 +237,8 @@ export type SubMenuType = { // TODO: 🎯Items Slots slots label 分组标题 horizontal // TODO: 🎯Items Slots slots label 分组标题 inline // TODO: 👀 Items Slots slots icon 菜单图标 vertical -// TODO: Items Slots slots icon 菜单图标 horizontal +// TODO: 👀 Items Slots slots icon 菜单图标 horizontal // TODO: 👀 Items Slots slots icon 菜单图标 inline // 🎯 TODO horizontal 缩略适配 -// 🎯 TODO 所有 👀 功能 +// 🎯 TODO 所有 👀 功能 分(exclude Items Slots slots icon 菜单图标 inline) diff --git a/preset/src/shortcuts/src/menu.ts b/preset/src/shortcuts/src/menu.ts index 2cc9ddcb..3105a7e2 100644 --- a/preset/src/shortcuts/src/menu.ts +++ b/preset/src/shortcuts/src/menu.ts @@ -17,14 +17,14 @@ export const menuShortcuts: Record = { 'k-menu-item-hover': 'hover:(ikun:6:bg-ikun-black)', 'k-menu-item-selected-after': - 'after:(content-empty pa bottom-0 bdb-2 border-solid b-b-ikun-main w-full left-0 animate-ikun-scale)', + 'after:(content-empty pa -bottom-1px bdb-2 border-solid b-b-ikun-main w-full left-0 animate-ikun-scale)', 'k-menu-item-selected-h': 'text-ikun-main k-menu-item-selected-after', 'k-menu-item-selected-group-h': 'text-ikun-main k-menu-item-selected-after', 'k-menu-item-hover-h': 'hover:(k-menu-item-selected-after)', 'k-menu-item-child': 'justify-between', - 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-vertical': 'bdr-1 b-e-solid border-ikun-bd-base overflow-hidden', 'k-menu-item-popover-trigger-vertical': 'box-border my-4px', 'k-menu-item-vertical': 'k-menu-item-inline my-0', 'k-menu-item-vertical-group': @@ -32,7 +32,7 @@ export const menuShortcuts: Record = { 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px ' + 'rounded-8px ikun:50:text-black', - 'k-menu-horizontal': 'bdb-1 b-e-solid border-ikun-bd-base flex [&.k-menu-sub-horizontal]:block', + 'k-menu-horizontal': 'bdb-1 b-solid border-ikun-bd-base flex [&.k-menu-sub-horizontal]:block', 'k-menu-item-popover-trigger-horizontal': 'box-border my-4px', 'k-menu-item-popover-content': 'p-0 box-border', 'k-menu-item-horizontal': @@ -44,8 +44,10 @@ export const menuShortcuts: Record = { 'k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px ' + 'rounded-8px ikun:50:text-black', + 'k-menu-item-popover-trigger-horizontal-divider': 'fcc', + 'k-menu-item-divider-horizontal': 'h-32px', - 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base', + 'k-menu-inline': 'bdr-1 b-e-solid border-ikun-bd-base overflow-hidden', 'k-menu-item-inline': 'cursor-pointer k-menu-w k-menu-transition ' + 'flex items-center pr h-40px leading-40px list-inside ps-16px p-ie-16px m-is-4px m-ie-4px my-4px ' + From 65dc2cb3e1f543bf2447a90fe5dd3ee59bbe3db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Tue, 23 Apr 2024 22:08:46 +0800 Subject: [PATCH 33/39] wip: complete KMenu component temp commit --- components/Menu/package.json | 1 + components/Menu/src/item.svelte | 53 +++++++++++++++++++++++++++----- components/Menu/src/types.d.ts | 17 +++++----- pnpm-lock.yaml | 3 ++ preset/src/shortcuts/src/menu.ts | 4 +-- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/components/Menu/package.json b/components/Menu/package.json index fac95ad4..4264c119 100644 --- a/components/Menu/package.json +++ b/components/Menu/package.json @@ -37,6 +37,7 @@ "@ikun-ui/divider": "workspace:*", "@ikun-ui/popover": "workspace:*", "baiwusanyu-utils": "^1.0.18", + "esm-env": "^1.0.0", "clsx": "^2.0.0", "svelte": "^4.2.7" }, diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 48cc1d79..c7921e07 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,5 +1,5 @@ {#if show} -
            - -
          +
          +
            + +
          +
          {/if} diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 08fbaca2..6030bea3 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -224,6 +224,9 @@ } } + + + let popoverRef: any = []; let subMenuRef: any = []; let isDirty = true; @@ -254,10 +257,12 @@ let parentDom: HTMLElement | null = null let itemEls: HTMLElement[] | null = null + let prevParentDomWidth = -1 + let ops = Array(items.length).fill(level === 1 ? '0' : '1'); if(BROWSER){ parentDom = document.querySelector('#bwsy'); if(parentDom){ - itemEls = (parentDom.querySelectorAll('[data-popover-trigger=""]')) + itemEls = Array.from((parentDom.querySelectorAll('[data-popover-trigger=""]'))) } } let moreItems: Array<{ @@ -268,53 +273,66 @@ function adjustLayout() { if(parentDom && level === 1){ const parentWidth = parentDom.offsetWidth; + let toS = false + let init = false + if(prevParentDomWidth === -1){ + init = true + prevParentDomWidth = parentWidth + } + + if(prevParentDomWidth < parentWidth){ + toS = false + } + + if(prevParentDomWidth > parentWidth){ + toS = true + } + prevParentDomWidth = parentWidth + let totalWidth = 0; - let childrenToMove: Array<{ - item: SubMenuType, - width: number, - index: number - }> = []; itemEls!.forEach((child: any, index: number) => { const offsetWidth = (child as HTMLElement).offsetWidth; totalWidth += offsetWidth - if (totalWidth > parentWidth) { + if (totalWidth > parentWidth && (toS || init)) { (child as HTMLElement).style.opacity = '0'; (child as HTMLElement).style.height = '0'; (child as HTMLElement).style.overflowY = 'hidden'; (child as HTMLElement).style.position = 'absolute'; (child as HTMLElement).style.pointerEvents = 'none'; - (child as HTMLElement).style.width = 'auto'; - childrenToMove.push({ + (child as HTMLElement).style.width = '0'; + const has = moreItems.some(it => it.index === index) + !has && moreItems.push({ index, item: itemsList[index], width:offsetWidth }); + init && (moreItems = moreItems.sort((a, b) => {return b.index - a.index})) + } else { + ops[index] = '1' } }); - if (childrenToMove.length > 0) { - // 将超出宽度的子节点从 Arr1 移到 Arr2 - moreItems = moreItems.concat(childrenToMove); - } else { - let spaceAvailable = parentWidth - totalWidth; - const moreItemsLen = moreItems.length - const lastItem = moreItems[moreItemsLen - 1] - if(lastItem){ - const lastItemWidth = lastItem.width - console.log(spaceAvailable, lastItemWidth) - if (moreItems.length > 0 && spaceAvailable >= lastItemWidth) { - const index = (moreItems.pop()!).index - const dom = itemEls![index] - if(dom){ - (dom as HTMLElement).style.opacity = '1'; - (dom as HTMLElement).style.width = '100'; - (dom as HTMLElement).style.removeProperty('height'); - (dom as HTMLElement).style.removeProperty('overflow-y'); - (dom as HTMLElement).style.removeProperty('position'); - (dom as HTMLElement).style.removeProperty('pointer-events'); - } - } - } + if(toS === false && !init){ + let spaceAvailable = Math.abs(totalWidth - parentWidth); + const moreItemsLen = moreItems.length + const lastItem = moreItems[moreItemsLen - 1] + if(lastItem){ + const lastItemWidth = lastItem.width + if (moreItems.length > 0 && spaceAvailable >= lastItemWidth) { + const index = (moreItems.pop()!).index + console.log(index) + const dom = itemEls![index] + if(dom){ + (dom as HTMLElement).style.opacity = '1'; + (dom as HTMLElement).style.width = '100'; + (dom as HTMLElement).style.removeProperty('height'); + (dom as HTMLElement).style.removeProperty('overflow-y'); + (dom as HTMLElement).style.removeProperty('position'); + (dom as HTMLElement).style.removeProperty('pointer-events'); + (dom as HTMLElement).style.removeProperty('width'); + } + } + } } } @@ -327,11 +345,12 @@ showPopoverManual(); } if (BROWSER && level === 1 && ctxProps.mode == 'horizontal') { - window.addEventListener('resize', adjustLayout); - await tick() adjustLayout(); + await tick() + window.addEventListener('resize', adjustLayout); // showPopoverManual(); } + menuCtx.removeBorderStyleBg() }); @@ -341,6 +360,9 @@ } }) + + + const menuPrefixCls = getPrefixCls('menu'); const prefixCls = getPrefixCls('menu-item'); $: cnames = (it: SubMenuType) => { @@ -583,6 +605,7 @@ width="100%" order={index} arrow={false} + opacity={ops[index]} placement={level === 1 ? 'bottom' : 'right'} on:animateStart={showSubMenuPopover} offset={setPopoverOffset} diff --git a/components/Menu/src/types.d.ts b/components/Menu/src/types.d.ts index d89c6fb0..ee624135 100644 --- a/components/Menu/src/types.d.ts +++ b/components/Menu/src/types.d.ts @@ -51,6 +51,7 @@ export type KMenuInstance = { onSelect: (param: SelectEvtPa) => void; onDeSelect: (param: SelectEvtPa) => void; onClick: (param: ClickEvtPa) => void; + removeBorderStyleBg: () => void }; export type KMenuProps = { @@ -241,6 +242,6 @@ export type SubMenuType = { // TODO: 👀 Items Slots slots icon 菜单图标 inline // 🎯 TODO horizontal 缩略适配 -// 🎯 TODO horizontal 缩略颤抖 -// 🎯 TODO horizontal 缩略与默认打开冲突 -// 🎯 TODO horizontal 获取父节点 +// -- 🎯 TODO 缩略重构 +// -- 🎯 TODO horizontal 缩略与默认打开冲突 +// -- 🎯 TODO horizontal 获取父节点 diff --git a/components/Menu/src/utils.ts b/components/Menu/src/utils.ts index 892c8d5d..45726f85 100644 --- a/components/Menu/src/utils.ts +++ b/components/Menu/src/utils.ts @@ -5,7 +5,8 @@ export const createKMenu = ( onOpenChange: KMenuInstance['onOpenChange'], onSelect: KMenuInstance['onSelect'], onClick: KMenuInstance['onClick'], - onDeSelect: KMenuInstance['onDeSelect'] + onDeSelect: KMenuInstance['onDeSelect'], + removeBorderStyleBg: KMenuInstance['removeBorderStyleBg'], ): KMenuInstance => { return { /** @@ -42,7 +43,8 @@ export const createKMenu = ( onOpenChange, onSelect, onClick, - onDeSelect + onDeSelect, + removeBorderStyleBg }; }; diff --git a/components/Popover/src/index.svelte b/components/Popover/src/index.svelte index f922c9a5..12142cce 100644 --- a/components/Popover/src/index.svelte +++ b/components/Popover/src/index.svelte @@ -23,6 +23,7 @@ export let width: KPopoverProps['width'] = 'fit-content'; export let order: undefined | number = undefined; export let offset: KPopoverProps['offset'] = [0, 8]; + export let opacity: string = '' export let fallbackPlacements: KPopoverProps['fallbackPlacements'] = [ 'top', 'right', @@ -214,6 +215,7 @@ class={triggerCls} style:width style:order={order} + style:opacity={opacity} data-popover-trigger on:mouseenter={handleMouseenter} on:mouseleave={handleMouseleave} From 275cd8de244c06cf07af3ef82a84782f43b79f4d Mon Sep 17 00:00:00 2001 From: baiwusanyu-c <740132583@qq.com> Date: Thu, 25 Apr 2024 15:39:59 +0800 Subject: [PATCH 36/39] wip: horizontal mode is turned on by default and is compatible with --- components/Menu/src/index.svelte | 32 ++++--- components/Menu/src/item.svelte | 126 ++++++++++++++-------------- components/Menu/src/types.d.ts | 8 +- components/Menu/src/utils.ts | 4 +- components/Popover/src/index.svelte | 8 +- preset/src/shortcuts/src/common.ts | 4 +- preset/src/shortcuts/src/menu.ts | 2 +- 7 files changed, 100 insertions(+), 84 deletions(-) diff --git a/components/Menu/src/index.svelte b/components/Menu/src/index.svelte index 3adad328..31298925 100644 --- a/components/Menu/src/index.svelte +++ b/components/Menu/src/index.svelte @@ -35,9 +35,16 @@ dispatch('deSelect', data); } - let bdBg = 'transparent' - function removeBorderStyleBg(){ - bdBg = '' + let bdBg = 'transparent'; + function removeBorderStyleBg() { + bdBg = ''; + } + + let menuRef: null | HTMLElement = null; + function getParentDom() { + if (menuRef) { + return menuRef.parentElement; + } } /** * @internal @@ -61,7 +68,8 @@ onSelect, onClick, onDeSelect, - removeBorderStyleBg + removeBorderStyleBg, + getParentDom ); if (!getContext(ctxKey || menuKey)) { setContext(ctxKey || menuKey, menuInst); @@ -90,15 +98,15 @@ {#if show} -
          +
          diff --git a/components/Menu/src/item.svelte b/components/Menu/src/item.svelte index 6030bea3..9a0aae95 100644 --- a/components/Menu/src/item.svelte +++ b/components/Menu/src/item.svelte @@ -1,5 +1,5 @@