From af9491e698dedf81bf024768c0e7327342001cfb Mon Sep 17 00:00:00 2001 From: xion Date: Sat, 2 Nov 2024 16:39:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/message/message.js | 0 apps/ui/docs/message.stories.js | 2 +- apps/ui/package.json | 4 +- apps/ui/src/components/message/message.ts | 90 +++++++++++++-------- apps/ui/src/components/modal/blank-modal.ts | 5 +- apps/ui/src/components/modal/modal.ts | 10 ++- apps/ui/src/components/utils/index.ts | 3 + apps/ui/src/components/utils/is.ts | 8 ++ apps/ui/src/components/utils/load-css.ts | 23 ++++++ apps/ui/src/utils/extra.ts | 5 ++ apps/ui/src/utils/store.ts | 4 +- apps/ui/theme/modal.mdx | 23 +++--- package.json | 6 +- pnpm-lock.yaml | 33 ++++++-- 14 files changed, 157 insertions(+), 59 deletions(-) delete mode 100644 apps/message/message.js create mode 100644 apps/ui/src/components/utils/index.ts create mode 100644 apps/ui/src/components/utils/is.ts create mode 100644 apps/ui/src/components/utils/load-css.ts diff --git a/apps/message/message.js b/apps/message/message.js deleted file mode 100644 index e69de29..0000000 diff --git a/apps/ui/docs/message.stories.js b/apps/ui/docs/message.stories.js index 6105290..b37cb68 100644 --- a/apps/ui/docs/message.stories.js +++ b/apps/ui/docs/message.stories.js @@ -1,4 +1,4 @@ -import { message as Message, createMessage } from '../deploy/message.js'; +import { message as Message, createMessage } from '../dist/message.js'; export default { title: 'ui/message', diff --git a/apps/ui/package.json b/apps/ui/package.json index c1af162..ed51033 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/system-ui", - "version": "0.0.1", + "version": "0.0.2", "description": "", "main": "dist/index.js", "privite": false, @@ -9,6 +9,7 @@ "dev": "rollup -c -w", "build": "npm run clean && rollup -c", "build:components": "rollup -c ./config/rollup.components.config.js", + "dev:components": "rollup -c ./config/rollup.components.config.js -w", "pub": "envision switchOrg system && envision deploy ./dist -v 0.0.2 -k ui -y y", "clean": "rimraf dist" }, @@ -33,6 +34,7 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", + "@types/lodash-es": "^4.17.12", "@types/postcss-import": "^14.0.3", "@types/react": "^18.3.8", "autoprefixer": "^10.4.20", diff --git a/apps/ui/src/components/message/message.ts b/apps/ui/src/components/message/message.ts index bbbc6eb..e1da26c 100644 --- a/apps/ui/src/components/message/message.ts +++ b/apps/ui/src/components/message/message.ts @@ -41,7 +41,7 @@ export class MessageContainer { } .message-wrapper { display: flex; - transition: transform 2s ease-in-out, opacity 1.2s ease-in-out; /* 缩小并淡出 */ + transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out; /* 缩小并淡出 */ } .message-wrapper:first-child { margin-top: 20px; @@ -49,15 +49,15 @@ export class MessageContainer { .message { display: flex; gap: 10px; - padding: 6px 10px; + padding: 4px 10px; margin: 0 auto; - border-radius: 4px; + border-radius: 8px; background-color: white; box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05); justify-content: center; - align-item: center; + align-items: center; animation: message-slide-down 0.3s ease-out forwards; /* 应用动画 */ } /* 添加消失类时 */ @@ -66,8 +66,6 @@ export class MessageContainer { opacity: 0; pointer-events: none; /* 防止交互 */ } - .message-success { - } @keyframes message-slide-down { 0% { transform: translateY(-100px); /* 从上方开始 */ @@ -87,6 +85,7 @@ export class MessageContainer { height: 24px; box-sizing: border-box; } + .message-icon::before { content: ""; position: absolute; @@ -95,27 +94,44 @@ export class MessageContainer { width: 5px; height: 10px; } + .icon-success { - border: 2px solid green; /* 外圆圈 */ + background: green; /* 背景颜色为绿色 */ + color: white; /* 文字颜色为白色 */ + border: 1px solid green; /* 外圆圈2 */ border-radius: 50%; /* 使其为圆形 */ + width: 20px; + height: 20px; + position: relative; + box-sizing: border-box; } + .icon-success::before { - border-right: 2px solid green; /* 打勾的右边部分 */ - border-bottom: 2px solid green; /* 打勾的下边部分 */ - transform: rotate(45deg); + content: ""; + position: absolute; + left: 7px; + top: 3px; + width: 5px; + height: 10px; + border-right: 2px solid white; /* 打勾的右边部分 */ + border-bottom: 2px solid white; /* 打勾的下边部分 */ + transform: rotate(45deg); /* 旋转形成勾形 */ + box-sizing: border-box; } .icon-info { - border: 2px solid blue; /* 外圆圈 */ + border: 1px solid blue; /* 外圆圈 */ border-radius: 50%; /* 使其为圆形 */ + background: blue; /* 背景颜色为蓝色 */ + width: 20px; + height: 20px; } .icon-info::before { content: "i"; position: absolute; - top: 0px; - color: blue; + top: -2px; + color: white; /* 文字颜色为白色 */ font-weight: bold; font-size: 16px; - left: 8px; } .icon-error::before, .icon-error::after { content: ""; @@ -123,13 +139,16 @@ export class MessageContainer { top: 4px; left: 50%; width: 2px; - height: 12px; - background-color: red; + height: 10px; + background-color: white; /* 线条颜色为白色 */ transform-origin: center; } .icon-error { - border: 2px solid red; /* 外圆圈 */ + border: 1px solid red; /* 外圆圈 */ border-radius: 50%; /* 使其为圆形 */ + background: red; /* 背景颜色为红色 */ + width: 20px; + height: 20px; } .icon-error::before { transform: translateX(-50%) rotate(45deg); /* 旋转形成叉号的一部分 */ @@ -139,29 +158,24 @@ export class MessageContainer { transform: translateX(-50%) rotate(-45deg); /* 旋转形成叉号的另一部分 */ } .icon-warning { - position: relative; - width: 0; - height: 0; - border-left: 12px solid transparent; - border-right: 12px solid transparent; - border-bottom: 24px solid orange; /* 三角形 */ - display: inline-block; - transform: scale(0.8); /* 缩小三角形 */ + border: 1px solid orange; /* 外圆圈 */ + border-radius: 50%; /* 使其为圆形 */ + background: orange; /* 背景颜色为蓝色 */ + width: 20px; + height: 20px; } .icon-warning::before { content: "!"; position: absolute; - top: 5px; - left: 50%; - transform: translateX(-50%); - color: white; + top: -2px; + color: white; /* 文字颜色为白色 */ font-weight: bold; font-size: 16px; } .icon-loading { - width: 24px; - height: 24px; + width: 20px; + height: 20px; border: 3px solid #f3f3f3; /* 边框颜色,用于加载圈的背景 */ border-top: 3px solid #3498db; /* 顶部边框的颜色,用于显示加载进度 */ border-radius: 50%; /* 圆形 */ @@ -188,7 +202,15 @@ export class MessageContainer { } const controller = new MessageContainer(); -export const createMessage = (content, opts) => { +type MessageOpts = { + /** w-20px h-20px */ + icon?: string; + key?: string; + style?: string; + className?: string; + type?: string; +}; +export const createMessage = (content: string | Element, opts: MessageOpts) => { let { icon, key, style, className, type } = opts || {}; const div = document.createElement('div'); div.className = 'message-wrapper' + (className ? ' ' + className : ''); @@ -211,7 +233,7 @@ export const createMessage = (content, opts) => { } if (content instanceof HTMLElement) { contentDiv.appendChild(content); - } else { + } else if (typeof content === 'string') { const text = document.createElement('span'); text.innerText = content; contentDiv.appendChild(text); @@ -227,7 +249,7 @@ export class Message { constructor() { this.controller = controller; } - open = (message, timeout = 3000, onClose, opts) => { + open = (message: string | Element, timeout = 3000, onClose, opts) => { const controller = this.controller; const div = createMessage(message, opts); const remove = () => { diff --git a/apps/ui/src/components/modal/blank-modal.ts b/apps/ui/src/components/modal/blank-modal.ts index ebbdfe1..9601e79 100644 --- a/apps/ui/src/components/modal/blank-modal.ts +++ b/apps/ui/src/components/modal/blank-modal.ts @@ -1,5 +1,5 @@ import { Modal, ModalOpts, KV } from './modal'; -import { SelectEl, querySelector, elAddCS, ElStyle, elAddCS2 } from '../../utils/query-el'; +import { SelectEl, querySelector, ElStyle, elAddCS2 } from '../../utils/query-el'; import { ObjCss } from '../../utils/css'; export class BlankModal extends Modal { @@ -8,15 +8,18 @@ export class BlankModal extends Modal { } } type DialogModalOpts = { + /** 标题的内容 */ dialogTitle?: string; dialogTitleClassName?: string; dialogTitleStyle?: ElStyle; dialogTitleEl?: HTMLElement; dialogTitleCloseIcon?: boolean; + /** 内容的模块 */ dialogContentClassName?: string; dialogContentStyle?: ElStyle; + /** Footer的模块 */ dialogFooterClassName?: string; dialogFooterStyle?: ElStyle; } & ModalOpts; diff --git a/apps/ui/src/components/modal/modal.ts b/apps/ui/src/components/modal/modal.ts index 29410ff..19bc627 100644 --- a/apps/ui/src/components/modal/modal.ts +++ b/apps/ui/src/components/modal/modal.ts @@ -1,4 +1,4 @@ -import { querySelector, elAddCS, ElStyle, elAddCS2 } from '../../utils/query-el'; +import { querySelector, ElStyle, elAddCS2 } from '../../utils/query-el'; import { generateId } from '../../utils/nanoid'; import { modalStore } from './store'; import { InitModalEvent } from './event'; @@ -28,6 +28,7 @@ export type ModalOpts< open?: boolean; onClose?: () => void; + /** 默认的样式属性, content style 和 mask style 等 */ defaultStyle?: DefaultStyle; } & T; export type DefaultStyle = { @@ -105,8 +106,8 @@ export class Modal { return _root; } - static render any>(this: T,el: string | HTMLDivElement, id: string, opts?: ConstructorParameters[0]): InstanceType; - static render any>(this: T,el: string | HTMLDivElement, opts?: ConstructorParameters[0]): InstanceType; + static render any>(this: T, el: string | HTMLDivElement, id: string, opts?: ConstructorParameters[0]): InstanceType; + static render any>(this: T, el: string | HTMLDivElement, opts?: ConstructorParameters[0]): InstanceType; static render(...args: any[]) { let [el, id, opts] = args; const _el = querySelector(el); @@ -142,7 +143,7 @@ export class Modal { _modal.renderEl(_el); return _modal; } - static create any>(this:T, opts: ModalOpts):InstanceType { + static create any>(this: T, opts: ModalOpts): InstanceType { let _id = opts.id; let _modal: Modal | undefined; const modalState = modalStore.getState(); @@ -169,6 +170,7 @@ export class Modal { return mask; } renderEl(el: HTMLDivElement) { + // base 的模块如果 defaultContentStyle 不存在,则使用默认的样式 const defaultContentStyle = this.defaultStyle?.defaultContentStyle || { position: 'absolute', padding: '20px', diff --git a/apps/ui/src/components/utils/index.ts b/apps/ui/src/components/utils/index.ts new file mode 100644 index 0000000..a8524b1 --- /dev/null +++ b/apps/ui/src/components/utils/index.ts @@ -0,0 +1,3 @@ +export * from './load-css'; + +export * from './is'; \ No newline at end of file diff --git a/apps/ui/src/components/utils/is.ts b/apps/ui/src/components/utils/is.ts new file mode 100644 index 0000000..1733935 --- /dev/null +++ b/apps/ui/src/components/utils/is.ts @@ -0,0 +1,8 @@ +import { isNil, isEmpty } from 'lodash-es'; + +/** + * Check if the value is null or empty object + */ +export const isObjectEmpty = (value: any) => { + return isNil(value) || isEmpty(value); +}; diff --git a/apps/ui/src/components/utils/load-css.ts b/apps/ui/src/components/utils/load-css.ts new file mode 100644 index 0000000..c99733d --- /dev/null +++ b/apps/ui/src/components/utils/load-css.ts @@ -0,0 +1,23 @@ +type LoadCSSOptions = { + key?: string; + url: string; + force?: boolean; +}; +export const loadCSS = (opts: LoadCSSOptions | string) => { + if (typeof opts === 'string') { + opts = { url: opts }; + } + const { key, url, force } = opts; + let cssKeyDom = document.querySelector('#load-css-' + key); + if (!force && key && cssKeyDom) { + // console.log('css already loaded', key); + return; + } else if (key && cssKeyDom) { + cssKeyDom.remove(); + } + const link = document.createElement('link'); + link.id = key ? 'load-css-' + key : ''; + link.rel = 'stylesheet'; + link.href = url; + document.head.appendChild(link); +}; diff --git a/apps/ui/src/utils/extra.ts b/apps/ui/src/utils/extra.ts index 70727c0..f340395 100644 --- a/apps/ui/src/utils/extra.ts +++ b/apps/ui/src/utils/extra.ts @@ -1,3 +1,8 @@ +/** + * 把字符串中的{{key}}替换成对应的值 + * @param text + * @returns + */ export function extractKeysFromBraces(text: string) { const regex = /\{\{\s*(.*?)\s*\}\}/g; const keys: string[] = []; diff --git a/apps/ui/src/utils/store.ts b/apps/ui/src/utils/store.ts index 2bf6460..46c58e9 100644 --- a/apps/ui/src/utils/store.ts +++ b/apps/ui/src/utils/store.ts @@ -1,3 +1,5 @@ import { createStore } from 'zustand/vanilla'; +import { shallow } from 'zustand/vanilla/shallow'; +export type { StateCreator, StoreApi } from 'zustand/vanilla'; -export { createStore }; +export { createStore, shallow }; diff --git a/apps/ui/theme/modal.mdx b/apps/ui/theme/modal.mdx index d371e85..f16eb16 100644 --- a/apps/ui/theme/modal.mdx +++ b/apps/ui/theme/modal.mdx @@ -1,14 +1,16 @@ -import { message } from '../deploy/message.js' -import { DialogModal } from '@kevisual/ui' -import '@kevisual/ui/dist/index.css' +import { message } from '../dist/message.js' +import { DialogModal } from '@kevisual/system-ui' +import '@kevisual/system-ui/dist/index.css' -Modal +# Modal > 使用原生js实现的弹窗组件 +安装 `npm i @kevisual/system-ui` + export const ShowModal = () => { - const url = 'https://kevisual.xiongxiao.me/system/theme/index.js' + const url = 'https://kevisual.xiongxiao.me/system/ui/index.js' const onClick = async () => { console.log('theme', DialogModal) @@ -44,11 +46,14 @@ export const ShowModal = () => { -使用方法 +*使用方法* + ```js -// import { DialogModal } from 'https://kevisual.xiongxiao.me/system/theme/index.js' -import { DialogModal } from '@kevisual/ui'; -import '@kevisual/ui/dist/index.css'; +// import { DialogModal, loadCss } from 'https://kevisual.xiongxiao.me/system/ui/index.js' +// loadCss('https://kevisual.xiongxiao.me/system/ui/index.css') + +import { DialogModal } from '@kevisual/system-ui'; +import '@kevisual/system-ui/dist/index.css'; const content = document.createElement('div'); content.innerHTML = ` diff --git a/package.json b/package.json index 59d195b..3569a61 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "tailwindcss": "^3.4.14" }, "dependencies": { - "@kevisual/ui": "^0.0.2", - "systemjs": "^6.15.1" + "@kevisual/system-ui": "^0.0.1", + "immer": "^10.1.1", + "systemjs": "^6.15.1", + "zustand": "5.0.0-rc.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d97567d..ffd0c81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: dependencies: - '@kevisual/ui': - specifier: ^0.0.2 - version: 0.0.2 + '@kevisual/system-ui': + specifier: ^0.0.1 + version: 0.0.1(rollup@4.24.0)(typescript@5.6.3) + immer: + specifier: ^10.1.1 + version: 10.1.1 systemjs: specifier: ^6.15.1 version: 6.15.1 + zustand: + specifier: 5.0.0-rc.2 + version: 5.0.0-rc.2(@types/react@18.3.11)(immer@10.1.1)(react@18.3.1) devDependencies: '@chromatic-com/storybook': specifier: ^2.0.2 @@ -102,6 +108,9 @@ importers: '@rollup/plugin-typescript': specifier: ^11.1.6 version: 11.1.6(rollup@4.24.0)(tslib@2.8.0)(typescript@5.6.3) + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 '@types/postcss-import': specifier: ^14.0.3 version: 14.0.3 @@ -493,8 +502,8 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@kevisual/ui@0.0.2': - resolution: {integrity: sha512-M47Z16TX5fN/lY8nvyN6y9CERXVvQ885Mi6hbSHythXuiay+GHO9FD4M6ib33LJlVpxQaVOmHwW3uD16h+pCdQ==} + '@kevisual/system-ui@0.0.1': + resolution: {integrity: sha512-TpIlzmft/4XsiCmIfEYSSqOCBoJR63W0l/ztnaIvJba1WymnysLdLniLsmKRLViOpxRg79wH5jlBoBP3UydEvg==} '@mdx-js/react@3.0.1': resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==} @@ -953,6 +962,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + '@types/lodash@4.17.11': resolution: {integrity: sha512-jzqWo/uQP/iqeGGTjhgFp2yaCrCYTauASQcpdzESNCkHjSprBJVcZP9KG9aQ0q+xcsXiKd/iuw/4dLjS3Odc7Q==} @@ -3573,11 +3585,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@kevisual/ui@0.0.2': + '@kevisual/system-ui@0.0.1(rollup@4.24.0)(typescript@5.6.3)': dependencies: dayjs: 1.11.13 + glob: 11.0.0 lodash-es: 4.17.21 + rollup-plugin-dts: 6.1.1(rollup@4.24.0)(typescript@5.6.3) style-to-object: 1.0.8 + transitivePeerDependencies: + - rollup + - typescript '@mdx-js/react@3.0.1(@types/react@18.3.11)(react@18.3.1)': dependencies: @@ -4108,6 +4125,10 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.11 + '@types/lodash@4.17.11': {} '@types/mdx@2.0.13': {}