diff --git a/.github/workflows/component-ci.yml b/.github/workflows/component-ci.yml index a1fbbe5..b7ab646 100644 --- a/.github/workflows/component-ci.yml +++ b/.github/workflows/component-ci.yml @@ -1,7 +1,7 @@ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages -name: Publish HankLiu-Design Components Into NPM +name: CI on: push: diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index be1722f..9427bc4 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -1,37 +1 @@ ---- -order: 6 -title: 更新日志 -toc: false -timeline: true ---- - -``` -🐞 Bug 修复 -💄 样式更新/less 变量更新 -🆕 新增特性 -🔥 极其值得关注的新增特性 -🇺🇸🇨🇳🇬🇧 国际化改动,注意这里直接用对应国家/地区的旗帜。 -📖 :memo: 文档或网站改进 -✅ 新增或更新测试用例 -🛎 更新警告/提示信息 -⌨️ :wheelchair: 可访问性增强 -🗑 废弃或移除 -🛠 重构或工具链优化 -⚡️ 性能提升 -``` - ---- - -## 0.0.2 - -- 🆕 新增 `Fullpage` 组件。 -- 🆕 新增 `Exception` 组件。 -- 🆕 新增 `Watermark` 组件。 -- 🛠 使用 `@hankliu/colors` 替换 `@ant-design/colors` 组件。 -- 🛠 使用 `@hankliu/icons` 替换 `@ant-design/icons` 组件,丰富 Icon 的图标库。 -- 🐞 修复使用 `@hankliu/hankliu-ui` 还需要在项目中额外安装 `react-color` 库的问题。 - -## 0.0.1 - -- 🐞 修复 DatePicker 样式依赖缺失 -- 🆕 Gallery 新增 sidebarPosition、showCount 属性 + diff --git a/UPDATE.zh-CN.md b/UPDATE.zh-CN.md index 8dbd29c..758f844 100644 --- a/UPDATE.zh-CN.md +++ b/UPDATE.zh-CN.md @@ -19,9 +19,30 @@ timeline: false 🛠 重构或工具链优化 ⚡️ 性能提升 ``` + --- ## 背景 开发一套基于 `AntDesign@4.x` 的 `React UI` 组件库,有自己的主题,丰富 `AntDesign` 的组件。 +## 0.0.3 + +- 🐞 `Watermark` 组件支持 `Modal` 和 `Drawer` 组件。 +- 🐞 `Watermark` 组件不存在 `lib/watermark/style/css` 的问题。 +- 🐞 `Fullpage` 组件不存在 `lib/fullpage/style/css` 的问题。 +- 🆕 新增 `dist` 文件夹,上传编译完整的文件,支持上传到 CDN 中。 + +## 0.0.2 + +- 🆕 新增 `Fullpage` 组件。 +- 🆕 新增 `Exception` 组件。 +- 🆕 新增 `Watermark` 组件。 +- 🛠 使用 `@hankliu/colors` 替换 `@ant-design/colors` 组件。 +- 🛠 使用 `@hankliu/icons` 替换 `@ant-design/icons` 组件,丰富 Icon 的图标库。 +- 🐞 修复使用 `@hankliu/hankliu-ui` 还需要在项目中额外安装 `react-color` 库的问题。 + +## 0.0.1 + +- 🐞 修复 DatePicker 样式依赖缺失 +- 🆕 Gallery 新增 sidebarPosition、showCount 属性 diff --git a/components/watermark/demo/portal.md b/components/watermark/demo/portal.md index 458c28b..eff62ec 100644 --- a/components/watermark/demo/portal.md +++ b/components/watermark/demo/portal.md @@ -32,10 +32,16 @@ const Placeholder = () => { const PortalWatermarkDemo = () => { const [showModal, setShowModal] = React.useState(false); + const [showModal2, setShowModal2] = React.useState(false); + const [showModal3, setShowModal3] = React.useState(false); + const [showModal4, setShowModal4] = React.useState(false); const [showDrawer, setShowDrawer] = React.useState(false); const [showDrawer2, setShowDrawer2] = React.useState(false); const closeModal = () => setShowModal(false); + const closeModal2 = () => setShowModal2(false); + const closeModal3 = () => setShowModal3(false); + const closeModal4 = () => setShowModal4(false); const closeDrawer = () => setShowDrawer(false); const closeDrawer2 = () => setShowDrawer2(false); @@ -45,6 +51,15 @@ const PortalWatermarkDemo = () => { + + + @@ -62,6 +77,9 @@ const PortalWatermarkDemo = () => { > {} + + {} + {} @@ -70,7 +88,19 @@ const PortalWatermarkDemo = () => { {} + + {} + + + {} + ); }; diff --git a/components/watermark/index.tsx b/components/watermark/index.tsx index 9ac3088..1cfeb68 100644 --- a/components/watermark/index.tsx +++ b/components/watermark/index.tsx @@ -126,7 +126,7 @@ const Watermark: React.FC = (props) => { // ============================ Content ============================= /** - * Get the width and height of the watermark. The default values are as follows + * 获得每一个水印印记的高度和宽度 * Image: [120, 64]; Content: It's calculated by content; */ const getMarkSize = (ctx: CanvasRenderingContext2D) => { @@ -136,14 +136,20 @@ const Watermark: React.FC = (props) => { ctx.font = `${parseInt(fontSize.toString())}px ${fontFamily}`; const contents = Array.isArray(content) ? content : [content]; const sizes = contents.map((item) => { + // measureText()方法可以度量字体的宽度。measureText()方法返回了一个包含width属性的TextMetrics对象 const metrics = ctx.measureText(item!); + // fontBoundingBoxAscent + fontBoundingBoxDescent 可以获得当前渲染文本的高度 + // fontBoundingBoxAscent: 属性标明的水平线到渲染文本的所有字体的矩形最高边界顶部的距离,使用 CSS 像素计算。 + // fontBoundingBoxDescent: 属性标明的水平线到渲染文本的所有字体的矩形边界最底部的距离,使用 CSS 像素计算。 return [metrics.width, metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent]; }); defaultWidth = Math.ceil(Math.max(...sizes.map((size) => size[0]))); defaultHeight = - Math.ceil(Math.max(...sizes.map((size) => size[1]))) * contents.length + - (contents.length - 1) * FontGap; + sizes.reduce((total, [_, height]) => total + height, 0) + (contents.length - 1) * FontGap; + // defaultHeight = + // Math.ceil(Math.max(...sizes.map((size) => size[1]))) * contents.length + + // (contents.length - 1) * FontGap; } return [width ?? defaultWidth, height ?? defaultHeight] as const; }; @@ -156,16 +162,20 @@ const Watermark: React.FC = (props) => { // Generate new Watermark content const renderWatermark = () => { - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); + // 主要用来判断是否能使用canvas + const ctx = document.createElement('canvas').getContext('2d'); if (ctx) { const ratio = getPixelRatio(); + // 获得每一个水印印记的大小 const [markWidth, markHeight] = getMarkSize(ctx); + // 绘制水印 const drawCanvas = ( + // 水印文字或者图片 drawContent?: NonNullable | HTMLImageElement, ) => { + // 获得水印的Base64格式的图片数据,以及区域的面积 const [nextClips, clipWidth] = getClips( drawContent || '', rotate, diff --git a/components/watermark/useClips.ts b/components/watermark/useClips.ts index 75d4d11..482e465 100644 --- a/components/watermark/useClips.ts +++ b/components/watermark/useClips.ts @@ -1,5 +1,6 @@ import type { WatermarkProps } from '.'; +// 垂直方向字体间距 export const FontGap = 3; function prepareCanvas( @@ -25,11 +26,23 @@ function prepareCanvas( } /** - * Get the clips of text content. - * This is a lazy hook function since SSR no need this + * 获取文本或者图片内容的水印图片剪辑。 + * Lazy 的钩子函数,在服务端渲染SSR的时候不要使用。 */ export default function useClips() { - // Get single clips + /** + * 获取文本或者图片内容的水印图片剪辑 + * + * @param content 文本或者图片内容 + * @param rotate 旋转角度 + * @param ratio 缩放大小 + * @param width mark宽度 + * @param height mark高度 + * @param font 字体样式 + * @param gapX 水平方向间距 + * @param gapY 垂直方向间距 + * @returns + */ function getClips( content: NonNullable | HTMLImageElement, rotate: number, diff --git a/index-style-only.js b/index-style-only.js new file mode 100644 index 0000000..0fe483b --- /dev/null +++ b/index-style-only.js @@ -0,0 +1,24 @@ +function pascalCase(name) { + return name.charAt(0).toUpperCase() + name.slice(1).replace(/-(\w)/g, (m, n) => n.toUpperCase()); +} + +// Just import style for https://github.com/ant-design/ant-design/issues/3745 +const req = require.context('./components', true, /^\.\/[^_][\w-]+\/style\/index\.tsx?$/); + +req.keys().forEach((mod) => { + let v = req(mod); + if (v && v.default) { + v = v.default; + } + const match = mod.match(/^\.\/([^_][\w-]+)\/index\.tsx?$/); + if (match && match[1]) { + if (match[1] === 'message' || match[1] === 'notification') { + // message & notification should not be capitalized + exports[match[1]] = v; + } else { + exports[pascalCase(match[1])] = v; + } + } +}); + +module.exports = exports; diff --git a/index-with-locales.js b/index-with-locales.js new file mode 100644 index 0000000..a4a4f88 --- /dev/null +++ b/index-with-locales.js @@ -0,0 +1,12 @@ +const hankliuUi = require('./components'); + +const req = require.context('./components', true, /^\.\/locale\/.+_.+\.tsx$/); + +hankliuUi.locales = {}; + +req.keys().forEach((mod) => { + const matches = mod.match(/\/([^/]+).tsx$/); + hankliuUi.locales[matches[1]] = req(mod).default; +}); + +module.exports = hankliuUi; diff --git a/index.js b/index.js new file mode 100644 index 0000000..bfa5047 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +require('./index-style-only'); + +module.exports = require('./components'); diff --git a/package.json b/package.json index 5b91789..ac76033 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@hankliu/hankliu-ui", - "version": "0.0.2", + "version": "0.0.3", "private": false, - "description": "HankLiu UI Components base on Ant-design@4.x", + "description": "🥭 HankLiu UI Components base on Ant-design@4.x", "files": [ "dist", "lib", @@ -16,12 +16,12 @@ ], "main": "lib/index.js", "module": "es/index.js", - "unpkg": "dist/antd.min.js", + "unpkg": "dist/hlui.min.js", "typings": "lib/index.d.ts", "scripts": { "start": "antd-tools run clean && cross-env NODE_ENV=development NODE_OPTIONS=--openssl-legacy-provider concurrently \"bisheng start -c ./site/bisheng.config.js\"", "clean": "antd-tools run clean && rm -rf es lib coverage dist report.html", - "compile": "npm run clean && antd-tools run compile", + "compile": "npm run clean && antd-tools run compile && antd-tools run dist", "dist": "antd-tools run dist", "prepublishOnlyNot": "npm run compile", "site": "rimraf _site && cross-env NODE_OPTIONS=--max_old_space_size=4096 NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production OUTPUT=_website bisheng build --ssr -c ./site/bisheng.config.js", @@ -90,7 +90,7 @@ "bisheng-plugin-description": "^0.1.4", "bisheng-plugin-react": "^1.2.3", "bisheng-plugin-toc": "^0.4.4", - "chalk": "^5.3.0", + "chalk": "^4.0.0", "concurrently": "^8.2.2", "cross-env": "^7.0.3", "docsearch.js": "^2.6.3", diff --git a/site/bisheng.config.js b/site/bisheng.config.js index db49aed..9a826c8 100644 --- a/site/bisheng.config.js +++ b/site/bisheng.config.js @@ -74,7 +74,7 @@ module.exports = { '@hankliu/hankliu-ui/lib': path.join(process.cwd(), 'components'), '@hankliu/hankliu-ui/es': path.join(process.cwd(), 'components'), // Change antd from `index.js` to `site/antd.js` to remove deps of root style - '@hankliu/hankliu-ui': path.join(process.cwd(), 'site', 'antd'), + '@hankliu/hankliu-ui': path.join(process.cwd(), 'site', 'hankliu'), site: path.join(process.cwd(), 'site'), 'react-router': 'react-router/umd/ReactRouter', }; @@ -179,7 +179,7 @@ module.exports = { }); config.module.rules.push({ - test: /\.(mp4)$/, + test: /\.(mp(4|3))$/, use: 'file-loader?name=video/[name].[ext]', }); diff --git a/site/antd.js b/site/hankliu.js similarity index 100% rename from site/antd.js rename to site/hankliu.js diff --git a/site/theme/template/Home/Page2.jsx b/site/theme/template/Home/Page2.jsx index facf0a5..60e5d85 100644 --- a/site/theme/template/Home/Page2.jsx +++ b/site/theme/template/Home/Page2.jsx @@ -118,14 +118,15 @@ export default function Page2({ isMobile, locale }) { const componentButton = (
- Ant Design of React + HankLiu UI of React + {/* - Ant Design of Angular + HankLiu UI of Angular - Ant Design of Vue - + HankLiu UI of Vue + */}
); const children = page2Data.map((item, i) => { diff --git a/site/theme/template/Layout/Header/Navigation.tsx b/site/theme/template/Layout/Header/Navigation.tsx index f67ad32..587a130 100644 --- a/site/theme/template/Layout/Header/Navigation.tsx +++ b/site/theme/template/Layout/Header/Navigation.tsx @@ -46,7 +46,7 @@ export default ({ let additional: React.ReactNode = null; const additionalItems = [ - + Github , @@ -93,7 +93,9 @@ export default ({ - github仓库 + + github仓库 + {additional} diff --git a/webpack.config.js b/webpack.config.js index 6a4dbba..91b387e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,8 +12,8 @@ const compactVars = require('./scripts/compact-vars'); const { webpack } = getWebpackConfig; function injectLessVariables(config, variables) { - (Array.isArray(config) ? config : [config]).forEach(conf => { - conf.module.rules.forEach(rule => { + (Array.isArray(config) ? config : [config]).forEach((conf) => { + conf.module.rules.forEach((rule) => { // filter less rule if (rule.test instanceof RegExp && rule.test.test('.less')) { const lessRule = rule.use[rule.use.length - 1]; @@ -43,8 +43,8 @@ function ignoreMomentLocale(webpackConfig) { } function addLocales(webpackConfig) { - let packageName = 'antd-with-locales'; - if (webpackConfig.entry['antd.min']) { + let packageName = 'hlui-with-locales'; + if (webpackConfig.entry['hlui.min']) { packageName += '.min'; } webpackConfig.entry[packageName] = './index-with-locales.js'; @@ -60,31 +60,13 @@ function externalMoment(config) { }; } -function injectWarningCondition(config) { - config.module.rules.forEach(rule => { - // Remove devWarning if needed - if (rule.test.test('test.tsx')) { - rule.use = [ - ...rule.use, - { - loader: 'string-replace-loader', - options: { - search: 'devWarning(', - replace: "if (process.env.NODE_ENV !== 'production') devWarning(", - }, - }, - ]; - } - }); -} - function processWebpackThemeConfig(themeConfig, theme, vars) { - themeConfig.forEach(config => { + themeConfig.forEach((config) => { ignoreMomentLocale(config); externalMoment(config); // rename default entry to ${theme} entry - Object.keys(config.entry).forEach(entryName => { + Object.keys(config.entry).forEach((entryName) => { const originPath = config.entry[entryName]; let replacedPath = [...originPath]; @@ -96,7 +78,7 @@ function processWebpackThemeConfig(themeConfig, theme, vars) { console.log(chalk.red('🆘 Seems entry has changed! It should be `./index`')); } - config.entry[entryName.replace('antd', `antd.${theme}`)] = replacedPath; + config.entry[entryName.replace('hlui', `hlui.${theme}`)] = replacedPath; delete config.entry[entryName]; }); @@ -109,10 +91,10 @@ function processWebpackThemeConfig(themeConfig, theme, vars) { after: { root: './dist', include: [ - `antd.${theme}.js`, - `antd.${theme}.js.map`, - `antd.${theme}.min.js`, - `antd.${theme}.min.js.map`, + `hlui.${theme}.js`, + `hlui.${theme}.js.map`, + `hlui.${theme}.min.js`, + `hlui.${theme}.min.js.map`, ], log: false, logWarning: false, @@ -132,12 +114,25 @@ const webpackVariableConfig = injectLessVariables(getWebpackConfig(false), { 'root-entry-name': 'variable', }); -webpackConfig.forEach(config => { - injectWarningCondition(config); -}); +for (const curConfig of [ + webpackConfig, + webpackDarkConfig, + webpackCompactConfig, + webpackVariableConfig, +]) { + for (const config of curConfig) { + for (const key in config.entry) { + if (/\@hankliu\/hankliu\-ui/.test(key)) { + const newKey = key.replace(/\@hankliu\/hankliu\-ui/, 'hlui'); + config.entry[newKey] = config.entry[key]; + delete config.entry[key]; + } + } + } +} if (process.env.RUN_ENV === 'PRODUCTION') { - webpackConfig.forEach(config => { + webpackConfig.forEach((config) => { ignoreMomentLocale(config); externalMoment(config); addLocales(config); @@ -151,13 +146,15 @@ if (process.env.RUN_ENV === 'PRODUCTION') { }); } - config.plugins.push( - new BundleAnalyzerPlugin({ - analyzerMode: 'static', - openAnalyzer: false, - reportFilename: '../report.html', - }), - ); + if (process.env.NODE_ENV === 'development') { + config.plugins.push( + new BundleAnalyzerPlugin({ + analyzerMode: 'static', + openAnalyzer: false, + reportFilename: '../report.html', + }), + ); + } if (!process.env.NO_DUP_CHECK) { config.plugins.push(