From 0a57ae66b33f0f68d5125f41097634f66211953b Mon Sep 17 00:00:00 2001 From: Tenny Date: Fri, 17 May 2024 17:51:20 +0800 Subject: [PATCH 01/18] =?UTF-8?q?feat(Checkbox):=20=E5=A4=8D=E9=80=89?= =?UTF-8?q?=E6=A1=86=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release-please.yml | 3 +- docs/.vitepress/config.ts | 1 + docs/.vitepress/theme/index.ts | 1 + docs/components/checkbox.md | 212 ++++++++++++++++ docs/components/table.md | 321 ++++++++++++++++++++++-- scripts/index.js | 4 +- src/components/Checkbox.vue | 72 ++++++ src/components/CheckboxButton.vue | 4 + src/components/CheckboxGroup.vue | 31 +++ src/components/Input.vue | 12 +- src/components/Table.vue | 360 ++++++++++++++++++--------- src/index.ts | 3 + style/checkbox/index.css | 126 ++++++++++ style/checkbox/index.js | 1 + 14 files changed, 1001 insertions(+), 150 deletions(-) create mode 100644 docs/components/checkbox.md create mode 100644 src/components/Checkbox.vue create mode 100644 src/components/CheckboxButton.vue create mode 100644 src/components/CheckboxGroup.vue create mode 100644 style/checkbox/index.css create mode 100644 style/checkbox/index.js diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 679d3396..3fc077b7 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -31,7 +31,8 @@ jobs: steps: - name: Print Previous Job Output run: | - echo "Previous job output: ${{ needs.release.outputs }}" + echo "Previous job output: " + echo "${{ needs.release.outputs }}" | jq . publish: runs-on: ubuntu-latest diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index b46b1737..a4393c76 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -52,6 +52,7 @@ export default defineConfig({ { text: 'Image 图片', link: '/components/image' }, { text: 'Shadow 阴影', link: '/components/shadow' }, { text: 'Table 表格', link: '/components/table' }, + { text: 'Checkbox 复选框', link: '/components/checkbox' }, ], }, ], diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 5e0d931b..4ecac9ef 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -19,6 +19,7 @@ import CodePreview from '../../../src/app_components/CodePreview.vue'; import '../../../style/message'; import '../../../style/shadow'; import '../../../style/table'; +import '../../../style/checkbox'; export default { extends: DefaultTheme, diff --git a/docs/components/checkbox.md b/docs/components/checkbox.md new file mode 100644 index 00000000..3eac14f5 --- /dev/null +++ b/docs/components/checkbox.md @@ -0,0 +1,212 @@ +# Checkbox 复选框 + +在一组备选项中进行多选。适用提醒用户勾选场景,突出多选框选项,可以有效增加用户识别度。 + +## 演示 + + + +### 基础用法 + +单独使用可以表示两种状态之间的切换;在 `nt-checkbox` 元素中定义 `v-model` 绑定变量,单一的 `checkbox` 中,默认绑定变量的值会是 `Boolean`,选中为 `true`。 + + + + + + + +### 禁用状态 + +多选框不可用状态, 设置 `disabled` 属性即可。 + + + + + + + +### 选项框组 + +使用 `nt-checkbox-group` 元素来包裹 `nt-checkbox` 元素,实现复选框组。使用时需要给 `nt-checkbox` 传递 `value` 属性。 + + + + + + + + +### 中间状态 + +设置 `indeterminate` 属性,表示不确定状态,一般用于实现全选的效果,实现部分选中的状态。 + + + + + + + + +### 按钮样式 + +只需要设置 `checkbox` 的 `type` 为 `button`;就能将复选框变为按钮样式 + + + + + + + + +## API + +### Checkbox Props + +| 参数 | 说明 | 类型 | 默认值 | +| ----------------------- | ------------------------------ | --------- | ------- | +| `model-value / v-model` | 选中项绑定的值 | `boolean` | - | +| `indeterminate` | 设置不确定状态,仅负责样式控制 | `boolean` | `false` | +| `name` | 原生 `name` 属性 | `string` | - | +| `disabled` | 是否禁用 | `boolean` | `false` | +| `value` | 原生 `value` 属性 | `string` | - | +| `label` | 显示的标签 | `string` | - | +| `type` | 是否设置为按钮风格 | `button` | - | + +### CheckboxGroup Props + +| 参数 | 说明 | 类型 | 默认值 | +| ----------------------- | -------------- | ---------- | ------ | +| `model-value / v-model` | 选中项绑定的值 | `string[]` | - | + +### Checkbox Events + +| 事件 | 说明 | 参数 | +| -------- | ---------------- | ---------------------------- | +| `change` | 选中项变化时触发 | `(checked: boolean) => void` | + +### CheckboxGroup Events + +| 事件 | 说明 | 参数 | +| -------- | ---------------- | ------------------------------- | +| `change` | 选中项变化时触发 | `(checkList: string[]) => void` | diff --git a/docs/components/table.md b/docs/components/table.md index 9fcc9cf1..e29ff53f 100644 --- a/docs/components/table.md +++ b/docs/components/table.md @@ -5,8 +5,8 @@ ## 演示 -> 1. 设置 `max-height` 可以通过直接设置 `style`;也可以通过 [tailwindcss-max-height](https://www.tailwindcss.cn/docs/max-height#setting-the-maximum-height) -> 2. 如果想改变滚动条样式,参考 [工具样式-滚动条](../css-util#_2-滚动条样式);引入样式表,然后给 `Table` 组件, 添加 `nt-scrollbar` 的类名: `` +> 1. _切记_: 要固定列,需要使用 `fixed` 布局,不能将 `table-layout` 设置为 `auto` +> 2. 设置 `max-height` 可以通过直接设置 `style`;也可以通过 [tailwindcss-max-height](https://www.tailwindcss.cn/docs/max-height#setting-the-maximum-height) +> 3. 如果想改变滚动条样式,参考 [工具样式-滚动条](../css-util#_2-滚动条样式);引入样式表,然后给 `Table` 组件, 添加 `nt-scrollbar` 的类名: `` ### 排序 @@ -383,31 +526,159 @@ +### 多级表头 + +配置 `columns` 的时候,给某一列增加一个 `children` 就能实现表头分组 + + + + + + + + +### 合并单元格 + +通过配置 `columns` 中的 `colspan`、`rowspan` 来实现合并单元格;当 `colspan` 或者 `rowspan` 为 `0` 时,则不显示当前单元格 + + + + + + + + +### 可编辑表格 + +通过自定义渲染的形式能够快速实现单元格的编辑 + + + + + + + + ## API ### Table Props -| 参数 | 说明 | 类型 | 默认值 | -| ---------------- | ---------------- | ------------------------ | ------- | -| `data` | 数据源 | `array` | - | -| `columns` | 表格列配置 | `ColumnOption[]` | - | -| `default-sort` | 初始排序 | `SortOption` | - | -| `stripe` | 是否为斑马纹 | `boolean` | `true` | -| `border` | 是否显示四周边框 | `boolean` | `false` | -| `fixed-head` | 是否固定表头 | `boolean` | `false` | -| `sorter` | 使用手动排序 | `(data: any[]) => any[]` | - | -| `render-summary` | 渲染表尾合计行 | `() => VNode \| VNode[]` | - | +| 参数 | 说明 | 类型 | 默认值 | +| ---------------- | ------------------------------ | ------------------------ | ------- | +| `data` | 数据源 | `array` | - | +| `columns` | 表格列配置 | `ColumnOption[]` | - | +| `default-sort` | 初始排序 | `SortOption` | - | +| `stripe` | 是否为斑马纹 | `boolean` | `true` | +| `border` | 是否显示四周边框 | `boolean` | `false` | +| `fixed-head` | 是否固定表头 | `boolean` | `false` | +| `sorter` | 使用手动排序 | `(data: any[]) => any[]` | - | +| `render-summary` | 渲染表尾合计行 | `() => VNode \| VNode[]` | - | +| `table-layout` | 表格的 `table-layout` 样式属性 | `fixed`、`auto` | `auto` | `ColumnOption` 选项: -| 字段 | 说明 | 类型 | 默认值 | -| -------- | ---------------------- | ----------------------------------------------- | ------- | -| `title` | 列名 | `string` | - | -| `key` | 列标识, 自动排序时必传 | `string` | - | -| `width` | 列宽 | `string`、`number` | - | -| `fixed` | 列是否固定 | `left`、`right` | - | -| `sorter` | 是否排序 | `boolean` | `false` | -| `render` | 自定义渲染 | `(row: any, index: number) => VNode \| VNode[]` | - | +| 字段 | 说明 | 类型 | 默认值 | +| -------------- | ---------------------- | -------------------------------------------------------- | ------- | +| `title` | 列名 | `string` | - | +| `key` | 列标识, 自动排序时必传 | `string` | - | +| `width` | 列宽 | `string`、`number` | - | +| `fixed` | 列是否固定 | `left`、`right` | - | +| `sorter` | 是否排序 | `boolean` | `false` | +| `render` | 自定义渲染 | `(row: any, index: number) => VNode \| VNode[]` | - | +| `titleRowspan` | 表头的行所占的行数 | `number` | - | +| `titleColspan` | 表头的单元格所占的列数 | `number` | - | +| `rowspan` | 单元格的 `rowspan` | `number` \| `(rowData: any, rowIndex: number) => number` | - | +| `colspan` | 单元格的 `colspan` | `number` \| `(rowData: any, rowIndex: number) => number` | - | `SortOption` 选项 diff --git a/scripts/index.js b/scripts/index.js index 074fd22a..ee342d44 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -60,13 +60,13 @@ async function createComponentTemplate(name) { '### 基础用法', '基础用法', '## API', - '### ${name} Props', + `### ${name} Props`, '| 参数 | 说明 | 类型 | 默认值 |', '| ---- | ---- | ---- | ---- |', '| x | x | x | x |', ]; await write( - path.join(process.cwd(), 'docs/components', `${name}.md`), + path.join(process.cwd(), 'docs/components', `${name.toUpperCase()}.md`), docTemplateContents.join('\r\n'), ); console.log('创建成功'); diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue new file mode 100644 index 00000000..0445e5ba --- /dev/null +++ b/src/components/Checkbox.vue @@ -0,0 +1,72 @@ + + diff --git a/src/components/CheckboxButton.vue b/src/components/CheckboxButton.vue new file mode 100644 index 00000000..be399d7e --- /dev/null +++ b/src/components/CheckboxButton.vue @@ -0,0 +1,4 @@ + + diff --git a/src/components/CheckboxGroup.vue b/src/components/CheckboxGroup.vue new file mode 100644 index 00000000..8f0da04c --- /dev/null +++ b/src/components/CheckboxGroup.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/components/Input.vue b/src/components/Input.vue index 756e0424..c8453e41 100644 --- a/src/components/Input.vue +++ b/src/components/Input.vue @@ -1,8 +1,18 @@ + +### 基础用法 + +当只有一个选项时,可以直接通过 `v-model` 绑定一个 `boolean` 值来控制是否选中;使用 `slot-label` 来重写选项的文字。 + + + + + + + + +### 禁用状态 + +设置 `disabled` 属性即可。 + + + + + + + +### 单选框组 + +结合 `nt-radio-group` 组件实现单选框组 + + + + + + + + +### 按钮样式 + +在单选框组基础上,设置 `nt-radio` 的 `type` 属性为 `button` 即可。 + + + + + + + + +## API + +### Radio Props + +| 参数 | 说明 | 类型 | 默认值 | +| ----------------------- | ------------------ | --------- | ------- | +| `model-value / v-model` | 是否选中 | `boolean` | x | +| `name` | 原生 `name` 属性 | `string` | - | +| `disabled` | 是否禁用 | `boolean` | `false` | +| `value` | 原生 `value` 属性 | `string` | - | +| `label` | 显示的标签 | `string` | - | +| `type` | 是否设置为按钮风格 | `button` | - | + +### RadioGroup Props + +| 参数 | 说明 | 类型 | 默认值 | +| ----------------------- | -------------- | -------- | ------ | +| `model-value / v-model` | 选中项绑定的值 | `string` | - | + +### Radio Events + +| 事件 | 说明 | 参数 | +| -------- | ---------------- | ---------------------------- | +| `change` | 选中项变化时触发 | `(checked: boolean) => void` | + +### RadioGroup Events + +| 事件 | 说明 | 参数 | +| -------- | ---------------- | -------------------------------- | +| `change` | 选中项变化时触发 | `(checkedValue: string) => void` | + +### Radio Slots + +| 名称 | 说明 | +| ------- | -------------- | +| `label` | 自定义文本内容 | diff --git a/scripts/index.js b/scripts/index.js index ee342d44..d24281f1 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -66,7 +66,7 @@ async function createComponentTemplate(name) { '| x | x | x | x |', ]; await write( - path.join(process.cwd(), 'docs/components', `${name.toUpperCase()}.md`), + path.join(process.cwd(), 'docs/components', `${name.toLowerCase()}.md`), docTemplateContents.join('\r\n'), ); console.log('创建成功'); diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue index 0445e5ba..d919ffce 100644 --- a/src/components/Checkbox.vue +++ b/src/components/Checkbox.vue @@ -48,7 +48,7 @@ const emits = defineEmits(['change']); const { checkList, updateCheck } = inject<{ checkList: Ref | null; updateCheck: null | ((value: any) => void); -}>('nt-check-group-check', { +}>('nt-checkbox-group-check', { checkList: null, updateCheck: null, }); diff --git a/src/components/CheckboxButton.vue b/src/components/CheckboxButton.vue deleted file mode 100644 index be399d7e..00000000 --- a/src/components/CheckboxButton.vue +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/src/components/CheckboxGroup.vue b/src/components/CheckboxGroup.vue index 8f0da04c..70064a82 100644 --- a/src/components/CheckboxGroup.vue +++ b/src/components/CheckboxGroup.vue @@ -1,7 +1,7 @@ @@ -718,7 +709,7 @@ diff --git a/package.json b/package.json index a8f714fa..e841b4ab 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ }, "license": "MulanPSL-2.0", "dependencies": { - "ph-utils": "^0.4.3", + "ph-utils": "^0.4.5", "qrcode-generator-es": "^0.0.4" }, "packageManager": "pnpm@9.0.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5a3d48c..fe3fdf3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: ph-utils: - specifier: ^0.4.3 - version: 0.4.3 + specifier: ^0.4.5 + version: 0.4.5 qrcode-generator-es: specifier: ^0.0.4 version: 0.0.4 @@ -152,6 +152,10 @@ packages: resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} + '@ctrl/tinycolor@4.1.0': + resolution: {integrity: sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ==} + engines: {node: '>=14'} + '@docsearch/css@3.6.0': resolution: {integrity: sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==} @@ -1194,8 +1198,8 @@ packages: perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - ph-utils@0.4.3: - resolution: {integrity: sha512-blFJ5+6QKoudds/zG2qEEGXJWRf/iSo24AqdIMQyj+JhrCMCZhQTF2uFCxJzYGhxhsbEurNsFI4He8rGfblY/Q==} + ph-utils@0.4.5: + resolution: {integrity: sha512-LmORf7AqiZSIP2ioQEwueNWYn7Wru7xo6Q8cJUw3a+/5xvLxS+gMdrsjzxCOpJBlcf4yKU9nEf6kb4RChSe0yw==} picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -1635,6 +1639,8 @@ snapshots: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + '@ctrl/tinycolor@4.1.0': {} + '@docsearch/css@3.6.0': {} '@docsearch/js@3.6.0(@algolia/client-search@4.23.3)(search-insights@2.13.0)': @@ -2689,7 +2695,9 @@ snapshots: perfect-debounce@1.0.0: {} - ph-utils@0.4.3: {} + ph-utils@0.4.5: + dependencies: + '@ctrl/tinycolor': 4.1.0 picocolors@1.0.0: {} diff --git a/src/components/Button.vue b/src/components/Button.vue index df438769..9f72cf92 100644 --- a/src/components/Button.vue +++ b/src/components/Button.vue @@ -7,9 +7,11 @@ round ? 'nt-btn-round' : '', circle ? 'nt-btn-circle' : '', loading ? 'nt-btn-loading' : '', + ghost ? 'nt-btn-ghost' : '', ]" :disabled="disabled || loading" :type="htmlType" + :style="colorStyle" > diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue index 3c996458..11aae90d 100644 --- a/src/components/Checkbox.vue +++ b/src/components/Checkbox.vue @@ -21,9 +21,9 @@ diff --git a/src/components/Radio.vue b/src/components/Radio.vue index cd913579..f91df280 100644 --- a/src/components/Radio.vue +++ b/src/components/Radio.vue @@ -23,9 +23,9 @@ diff --git a/src/components/Table.vue b/src/components/Table.vue index fd63a704..97377b91 100644 --- a/src/components/Table.vue +++ b/src/components/Table.vue @@ -3,6 +3,8 @@ import { defineComponent, h, PropType, ref, watch } from 'vue'; import type { VNode } from 'vue'; import Radio from './Radio.vue'; import Checkbox from './Checkbox.vue'; +import { random } from 'ph-utils'; +import { format } from 'ph-utils/date'; export interface ColumnOption { /** 排序时,如果传递了 key,则会将此 key 回传,便于排序, 如果不传此 key,则排序无效 */ @@ -29,6 +31,8 @@ export interface ColumnOption { titleRowspan: number; /** 设置可选择 */ type?: 'radio' | 'checkbox'; + /** 为 radio,checkbox 设置是否禁用 */ + disabled?: (row: any) => boolean; } export interface DataSortState { @@ -44,6 +48,8 @@ interface SortOption { type SorterFnOption = (data: any[]) => any[]; +type RowKeyOption = (row: any) => any; + /** 通过配置的 columns 计算表头跨行,跨列 */ function calculateSpan(headers: ColumnOption[], level = 0): ColumnOption[] { if (!Array.isArray(headers)) { @@ -145,14 +151,23 @@ export default defineComponent({ required: false, default: 'auto', }, + rowKey: { + type: Function as PropType, + required: false, + }, }, setup(props) { const sortInfo = ref({ key: '', order: '', }); + const allowSelectCount = calcAllowSelectCount(); // 允许选择的数量 const sourceData = ref(props.data); const parsedColumns = calculateSpan(props.columns, 0); + const selectedValues = new Set(); + /** 复选的半选、全选状态 */ + const isIndeterminate = ref(false); + const checkedAll = ref(false); watch( () => props.data, @@ -161,6 +176,45 @@ export default defineComponent({ }, ); + function calcAllowSelectCount() { + let c = 0; + if (props.columns[0].type === 'checkbox') { + for (const d in props.data) { + let isDisabled = false; + if (props.columns[0].disabled != null) { + isDisabled = props.columns[0].disabled(d); + } + if (!isDisabled) { + c++; + } + } + } + return c; + } + + function handleSelectionChange(value: any) { + const selectType = props.columns[0].type; + if (selectType === 'radio') { + selectedValues.clear(); + } + if (selectedValues.has(value)) { + selectedValues.delete(value); + } else { + selectedValues.add(value); + } + if (selectedValues.size === 0) { + isIndeterminate.value = false; + checkedAll.value = false; + } else if (selectedValues.size === allowSelectCount) { + checkedAll.value = true; + isIndeterminate.value = false; + } else { + checkedAll.value = false; + isIndeterminate.value = true; + } + console.log(selectedValues); + } + function dataSort( data: any[], sortInfo: SortOption, @@ -273,7 +327,17 @@ export default defineComponent({ if (column.type != null) { if (column.type === 'checkbox') { colChildren.push( - h('div', { class: 'nt-table-selection-cell' }, h(Checkbox)), + h( + 'div', + { + class: 'nt-table-selection-cell', + }, + h(Checkbox, { + indeterminate: isIndeterminate.value, + checked: checkedAll.value, + onChange: handleSelectionChange, + }), + ), ); } } else { @@ -324,6 +388,7 @@ export default defineComponent({ left: string[], right: string[], rowChildren: VNode[], + selectionName: string, ) { for (const column of columns) { if (column.children == null) { @@ -383,6 +448,8 @@ export default defineComponent({ } else if (column.key != null) { rowChildren.push(h('td', tdAttr, rowData[column.key])); } else if (column.type != null) { + const selectionValue = + props.rowKey != null ? props.rowKey(rowData) : ''; rowChildren.push( h( 'td', @@ -390,7 +457,15 @@ export default defineComponent({ h( 'div', { class: 'nt-table-selection-cell' }, - h(column.type === 'radio' ? Radio : Checkbox), + h(column.type === 'radio' ? Radio : Checkbox, { + name: selectionName, + value: selectionValue, + checked: selectedValues.has(selectionValue), + disabled: column.disabled + ? column.disabled(rowData) + : false, + onChange: handleSelectionChange, + }), ), ), ); @@ -406,6 +481,7 @@ export default defineComponent({ left, right, rowChildren, + selectionName, ); } } @@ -413,10 +489,12 @@ export default defineComponent({ function renderBody() { const bodies: VNode[] = []; + format(); + const selectionName = `${random(3)}${String(Date.now()).substring(8)}`; for (let i = 0, len = sourceData.value.length; i < len; i++) { const dataItem = sourceData.value[i]; const $tds: VNode[] = []; - renderBodyRow(parsedColumns, i, dataItem, [], [], $tds); + renderBodyRow(parsedColumns, i, dataItem, [], [], $tds, selectionName); bodies.push(h('tr', $tds)); } return bodies; diff --git a/src/style.css b/src/style.css index 4ffd3be7..0ed49682 100644 --- a/src/style.css +++ b/src/style.css @@ -106,6 +106,21 @@ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); } +.nt-btn-blue { + --nt-btn-border-color: #1677ff; + --nt-btn-hover-border-color: #4096ff; + --nt-btn-active-border-color: #0958d9; +} + +.nt-btn-gradient { + border: none; + --nt-btn-color: #389e0d; + --nt-btn-active-color: #0fd850; + --nt-btn-background: linear-gradient(90deg, #0fd850 0%, #f9f047 100%); + --nt-btn-hover-background: linear-gradient(90deg, #2af06a 0%, #fbf478 100%); + --nt-btn-active-background: linear-gradient(90deg, #0a9036 0%, #ece008 100%); +} + #app { .icon-list { display: inline-grid; diff --git a/style/button/index.css b/style/button/index.css index c2b4d2b0..8223310b 100644 --- a/style/button/index.css +++ b/style/button/index.css @@ -1,18 +1,22 @@ /* 默认按钮,按钮的基础样式 */ .nt-btn { /* 按钮的文字颜色 */ - --nt-btn-color: rgba(0, 0, 0, 0.65); + --nt-btn-color: #ffffff; + --nt-btn-hover-color: var(--nt-btn-color); + --nt-btn-active-color: var(--nt-btn-color); /* 按钮的背景色 */ - --nt-btn-bg-color: #fff; /* 按钮的边框颜色 */ - --nt-btn-border-color: #d9d9d9; + --nt-btn-border-color: var(--nt-primary-color, #52c41a); + --nt-btn-background: var(--nt-btn-border-color); /* 按钮的悬浮边框 less lighten(var(--nt-primary-color), 10) */ - --nt-btn-hover-color: var(--nt-primary-color-light1, #31890a); + --nt-btn-hover-border-color: var(--nt-primary-color-light1, #31890a); + --nt-btn-hover-background: var(--nt-btn-hover-border-color); /* 按钮的点击颜色 */ - --nt-btn-active-color: var(--nt-primary-color-dark1, #31890a); + --nt-btn-active-border-color: var(--nt-primary-color-dark1, #31890a); + --nt-btn-active-background: var(--nt-btn-active-border-color); /* 按钮禁用 */ --nt-btn-disabled-color: #c9c9c9; - --nt-btn-disabled-bg-color: #fbfbfb; + --nt-btn-disabled-background: #fbfbfb; --nt-btn-disabled-border-color: #e6e6e6; display: inline-flex; justify-content: center; @@ -27,7 +31,7 @@ border-radius: 3px; font-size: 14px; color: var(--nt-btn-color); - background: var(--nt-btn-bg-color); + background: var(--nt-btn-background); border: 1px solid var(--nt-btn-border-color); transition: border-color 0.3s, @@ -49,43 +53,58 @@ } .nt-btn:hover { - border-color: var(--nt-btn-hover-border-color, var(--nt-btn-hover-color)); + border-color: var( + --nt-btn-hover-border-color, + var(--nt-btn-hover-background) + ); color: var(--nt-btn-hover-color); - background-color: var(--nt-btn-hover-bg-color, var(--nt-btn-bg-color)); + background: var(--nt-btn-hover-background); } .nt-btn:active { - border-color: var(--nt-btn-active-border-color, var(--nt-btn-active-color)); + border-color: var( + --nt-btn-active-border-color, + var(--nt-btn-active-background) + ); color: var(--nt-btn-active-color); - background-color: var(--nt-btn-active-bg-color, var(--nt-btn-bg-color)); + background: var(--nt-btn-active-background); } .nt-btn [class*='nt-icon'] + span { margin-left: 5px; } +.nt-btn-normal { + /* 按钮的文字颜色 */ + --nt-btn-color: rgba(0, 0, 0, 0.65); + /* 按钮的背景色 */ + --nt-btn-background: #fff; + /* 按钮的边框颜色 */ + --nt-btn-border-color: #d9d9d9; + /* 按钮的悬浮边框 less lighten(var(--nt-primary-color), 10) */ + --nt-btn-hover-color: var(--nt-primary-color-light1, #31890a); + /* 按钮的点击颜色 */ + --nt-btn-active-color: var(--nt-primary-color-dark1, #31890a); + --nt-btn-hover-background: transparent; + --nt-btn-active-background: transparent; + --nt-btn-hover-border-color: var(--nt-btn-hover-color); + --nt-btn-active-border-color: var(--nt-btn-active-color); +} + /* primary 按钮样式 */ .nt-btn-primary { - /* 按钮的颜色 */ - --nt-btn-color: #fff; /* 按钮的背景色 */ - --nt-btn-bg-color: var(--nt-primary-color); + --nt-btn-background: var(--nt-primary-color); /* 按钮的边框颜色 */ - --nt-btn-border-color: var(--nt-primary-color); - /* 按钮的悬浮边框 less lighten(var(--nt-primary-color), 10) */ - --nt-btn-hover-color: #fff; - --nt-btn-hover-border-color: var(--nt-primary-color-light1, #31890a); - --nt-btn-hover-bg-color: var(--nt-primary-color-light1, #31890a); + --nt-btn-hover-background: var(--nt-primary-color-light1, #31890a); /* 按钮的点击颜色 */ - --nt-btn-active-color: #fff; - --nt-btn-active-border-color: var(--nt-primary-color-dark1, #31890a); - --nt-btn-active-bg-color: var(--nt-primary-color-dark1, #31890a); + --nt-btn-active-background: var(--nt-primary-color-dark1, #31890a); } /* 按钮禁用时的样式 */ .nt-btn:not(.nt-btn-loading):disabled { border-color: var(--nt-btn-disabled-border-color); - background-color: var(--nt-btn-disabled-bg-color); + background: var(--nt-btn-disabled-background); color: var(--nt-btn-disabled-color); cursor: not-allowed; opacity: 1; @@ -96,17 +115,32 @@ /* 按钮的颜色 */ --nt-btn-color: var(--nt-primary-color); /* 按钮的背景色 */ - --nt-btn-bg-color: transparent; + --nt-btn-background: transparent; /* 按钮的边框颜色 */ --nt-btn-border-color: transparent; --nt-btn-hover-border-color: transparent; --nt-btn-active-border-color: transparent; - --nt-btn-disabled-bg-color: transparent; + --nt-btn-disabled-background: transparent; --nt-btn-disabled-border-color: transparent; + --nt-btn-hover-background: transparent; + --nt-btn-active-background: transparent; height: auto; padding: 5px; } +.nt-btn-ghost { + /* 按钮的颜色 */ + --nt-btn-color: var(--nt-btn-border-color); + /* 按钮的背景色 */ + --nt-btn-background: transparent; + --nt-btn-hover-background: transparent; + --nt-btn-active-background: transparent; + /* 按钮的悬浮边框 less lighten(var(--nt-primary-color), 10) */ + --nt-btn-hover-color: var(--nt-btn-hover-border-color); + /* 按钮的点击颜色 */ + --nt-btn-active-color: var(--nt-btn-active-border-color); +} + /* 高度圆形按钮 */ .nt-btn-round { border-radius: calc(var(--nt-form-edit-height) / 2); diff --git a/style/table/index.js b/style/table/index.js index 4582418a..d0899589 100644 --- a/style/table/index.js +++ b/style/table/index.js @@ -1 +1,3 @@ -import "./index.css"; \ No newline at end of file +import './index.css'; +import '../radio'; +import '../checkbox'; From cdaa8b106ffa40f5c67cf2724f0e9d9e13ca4603 Mon Sep 17 00:00:00 2001 From: fly_dream <1456207945@qq.com> Date: Thu, 30 May 2024 16:46:17 +0800 Subject: [PATCH 12/18] chore(main): release 0.5.2 (#14) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bba9bf..bb21787c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.2](https://github.com/DvShu/neatui-vue/compare/v0.5.1...v0.5.2) (2024-05-30) + + +### Bug Fixes + +* **Button:** 按钮增加曾定义颜色功能 ([3d7ea23](https://github.com/DvShu/neatui-vue/commit/3d7ea23490f5113299cda3e26f99945ecc8c382c)) + ## [0.5.1](https://github.com/DvShu/neatui-vue/compare/v0.5.0...v0.5.1) (2024-05-24) diff --git a/package.json b/package.json index e841b4ab..591b5f64 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asteres/neatui-vue", "description": "基于 Vue3 的 UI 组件库", - "version": "0.5.1", + "version": "0.5.2", "type": "module", "scripts": { "g:c": "node scripts/index.js template", From 34785b81c35d7e43b4b3e00f97ac83db449828ba Mon Sep 17 00:00:00 2001 From: Tenny Date: Thu, 30 May 2024 16:52:07 +0800 Subject: [PATCH 13/18] =?UTF-8?q?ci:=20=E6=9B=B4=E6=96=B0=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Checkbox.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue index 11aae90d..a670198a 100644 --- a/src/components/Checkbox.vue +++ b/src/components/Checkbox.vue @@ -57,7 +57,7 @@ const { checkList, updateCheck } = inject<{ updateCheck: null, }); -function initIsChecked() { +function initIsChecked(): boolean { if (props.checked != null) { return props.checked; } @@ -67,14 +67,14 @@ function initIsChecked() { if (props.value != null) { return checkedModel.value === props.value; } - return checkedModel.value; + return checkedModel.value as boolean; } const isChecked = ref(initIsChecked()); watch( () => props.checked, (checked) => { - isChecked.value = checked; + isChecked.value = checked as boolean; }, ); From 5d01b1de256bb499184c7f9e1c349308035dea10 Mon Sep 17 00:00:00 2001 From: Tenny Date: Thu, 30 May 2024 16:57:05 +0800 Subject: [PATCH 14/18] =?UTF-8?q?type(Radio):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Checkbox.vue | 2 +- src/components/Radio.vue | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue index a670198a..c5922b09 100644 --- a/src/components/Checkbox.vue +++ b/src/components/Checkbox.vue @@ -69,7 +69,7 @@ function initIsChecked(): boolean { } return checkedModel.value as boolean; } -const isChecked = ref(initIsChecked()); +const isChecked = ref(initIsChecked()); watch( () => props.checked, diff --git a/src/components/Radio.vue b/src/components/Radio.vue index f91df280..dc24d250 100644 --- a/src/components/Radio.vue +++ b/src/components/Radio.vue @@ -52,7 +52,7 @@ const { checkedValue, updateCheck } = inject<{ updateCheck: null, }); -function initIsChecked() { +function initIsChecked(): boolean { if (props.checked != null) { return props.checked; } @@ -62,7 +62,7 @@ function initIsChecked() { if (props.value != null) { return checkedModel.value === props.value; } - return checkedModel.value; + return checkedModel.value as boolean; } const isChecked = ref(initIsChecked()); @@ -70,7 +70,7 @@ const isChecked = ref(initIsChecked()); watch( () => props.checked, (val) => { - isChecked.value = val; + isChecked.value = val as boolean; }, ); From f18a31f487d7c16906290f5e561bd3aa187ba602 Mon Sep 17 00:00:00 2001 From: Tenny Date: Fri, 7 Jun 2024 09:53:18 +0800 Subject: [PATCH 15/18] =?UTF-8?q?fix(Table):=20=E4=BC=98=E5=8C=96=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(Icon): 增加 ArrowUp、ArrowDown 组件 --- .github/workflows/release-please.yml | 8 +++++ docs/components/table.md | 18 +++++++++-- src/components/Table.vue | 48 ++++++++++++++++++---------- src/components/icon/ArrowDown.vue | 12 +++++++ src/components/icon/ArrowUp.vue | 12 +++++++ 5 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 src/components/icon/ArrowDown.vue create mode 100644 src/components/icon/ArrowUp.vue diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 0c1d2853..5772c81e 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest outputs: release_created: ${{ steps.release.outputs.release_created }} + job_output: ${{ steps.set-output-step.outputs.output_value }} steps: - uses: googleapis/release-please-action@v4 id: release @@ -27,6 +28,13 @@ jobs: # for more options release-type: node + - name: Generate output value + id: set-output-step + run: | + echo "Generating output value..." + VALUE="Hello, World!" + echo "::set-output name=output_value::$VALUE" + joblog: runs-on: ubuntu-latest needs: release diff --git a/docs/components/table.md b/docs/components/table.md index 5c0e5d05..5ed90f8f 100644 --- a/docs/components/table.md +++ b/docs/components/table.md @@ -314,6 +314,10 @@ function rowKey(rowData) { return rowData.name } + + function handleSelectChange(v) { + console.log(v) + } ### 基础表格 @@ -692,7 +696,12 @@ @@ -709,7 +718,12 @@ diff --git a/src/components/Table.vue b/src/components/Table.vue index 97377b91..d68ad726 100644 --- a/src/components/Table.vue +++ b/src/components/Table.vue @@ -156,15 +156,16 @@ export default defineComponent({ required: false, }, }, - setup(props) { + emits: ['select-change'], + setup(props, { emit }) { const sortInfo = ref({ key: '', order: '', }); - const allowSelectCount = calcAllowSelectCount(); // 允许选择的数量 + const allowSelect = calcAllowSelect(); // 允许选择的列表 const sourceData = ref(props.data); const parsedColumns = calculateSpan(props.columns, 0); - const selectedValues = new Set(); + const selectedValues = ref([]); /** 复选的半选、全选状态 */ const isIndeterminate = ref(false); const checkedAll = ref(false); @@ -176,16 +177,16 @@ export default defineComponent({ }, ); - function calcAllowSelectCount() { - let c = 0; + function calcAllowSelect() { + let c = []; if (props.columns[0].type === 'checkbox') { - for (const d in props.data) { + for (const d of props.data) { let isDisabled = false; if (props.columns[0].disabled != null) { isDisabled = props.columns[0].disabled(d); } - if (!isDisabled) { - c++; + if (!isDisabled && props.rowKey != null) { + c.push(props.rowKey(d)); } } } @@ -195,24 +196,37 @@ export default defineComponent({ function handleSelectionChange(value: any) { const selectType = props.columns[0].type; if (selectType === 'radio') { - selectedValues.clear(); + selectedValues.value = []; } - if (selectedValues.has(value)) { - selectedValues.delete(value); + let index = selectedValues.value.indexOf(value); + if (index !== -1) { + selectedValues.value.splice(index, 1); } else { - selectedValues.add(value); + selectedValues.value.push(value); } - if (selectedValues.size === 0) { + if (selectedValues.value.length === 0) { isIndeterminate.value = false; checkedAll.value = false; - } else if (selectedValues.size === allowSelectCount) { + } else if (selectedValues.value.length === allowSelect.length) { checkedAll.value = true; isIndeterminate.value = false; } else { checkedAll.value = false; isIndeterminate.value = true; } - console.log(selectedValues); + emit('select-change', [...selectedValues.value]); + } + + function handleChangeAll(v: boolean) { + if (v === true) { + selectedValues.value = [...allowSelect]; + checkedAll.value = true; + } else { + selectedValues.value = []; + checkedAll.value = false; + } + isIndeterminate.value = false; + emit('select-change', [...selectedValues.value]); } function dataSort( @@ -335,7 +349,7 @@ export default defineComponent({ h(Checkbox, { indeterminate: isIndeterminate.value, checked: checkedAll.value, - onChange: handleSelectionChange, + onChange: handleChangeAll, }), ), ); @@ -460,7 +474,7 @@ export default defineComponent({ h(column.type === 'radio' ? Radio : Checkbox, { name: selectionName, value: selectionValue, - checked: selectedValues.has(selectionValue), + checked: selectedValues.value.includes(selectionValue), disabled: column.disabled ? column.disabled(rowData) : false, diff --git a/src/components/icon/ArrowDown.vue b/src/components/icon/ArrowDown.vue new file mode 100644 index 00000000..e387ffbd --- /dev/null +++ b/src/components/icon/ArrowDown.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/components/icon/ArrowUp.vue b/src/components/icon/ArrowUp.vue new file mode 100644 index 00000000..8a70b287 --- /dev/null +++ b/src/components/icon/ArrowUp.vue @@ -0,0 +1,12 @@ + + + From a8b060363ebc67a980a6592d8af19db919553881 Mon Sep 17 00:00:00 2001 From: fly_dream <1456207945@qq.com> Date: Fri, 7 Jun 2024 09:55:14 +0800 Subject: [PATCH 16/18] chore(main): release 0.5.3 (#15) --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb21787c..b8254722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.5.3](https://github.com/DvShu/neatui-vue/compare/v0.5.2...v0.5.3) (2024-06-07) + + +### Bug Fixes + +* **Icon:** 增加 ArrowUp、ArrowDown 组件 ([f18a31f](https://github.com/DvShu/neatui-vue/commit/f18a31f487d7c16906290f5e561bd3aa187ba602)) +* **Table:** 优化表格 ([f18a31f](https://github.com/DvShu/neatui-vue/commit/f18a31f487d7c16906290f5e561bd3aa187ba602)) + ## [0.5.2](https://github.com/DvShu/neatui-vue/compare/v0.5.1...v0.5.2) (2024-05-30) diff --git a/package.json b/package.json index 591b5f64..7353b4dd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asteres/neatui-vue", "description": "基于 Vue3 的 UI 组件库", - "version": "0.5.2", + "version": "0.5.3", "type": "module", "scripts": { "g:c": "node scripts/index.js template", From 404aac00600084214276e9d38b29a267b1b5638c Mon Sep 17 00:00:00 2001 From: Tenny Date: Fri, 7 Jun 2024 11:08:49 +0800 Subject: [PATCH 17/18] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=8A?= =?UTF-8?q?=E4=B8=AA=E7=89=88=E6=9C=AC=E6=9C=AA=E6=AD=A3=E7=A1=AE=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci: 优化CI --- .github/workflows/release-please.yml | 2 ++ src/index.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 5772c81e..03a0d74a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -33,7 +33,9 @@ jobs: run: | echo "Generating output value..." VALUE="Hello, World!" + release_created=${{ steps.release.outputs.release_created }} echo "::set-output name=output_value::$VALUE" + echo "::set-output name=release_created::$release_created" joblog: runs-on: ubuntu-latest diff --git a/src/index.ts b/src/index.ts index 9b68e106..63c31cc8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,8 @@ export { default as CaretTopIcon } from './components/icon/CaretTop.vue'; export { default as CaretBottomIcon } from './components/icon/CaretBottom.vue'; export { default as ArrowLeftIcon } from './components/icon/ArrowLeft.vue'; export { default as ArrowRightIcon } from './components/icon/ArrowRight.vue'; +export { default as ArrowUpIcon } from './components/icon/ArrowUp.vue'; +export { default as ArrowDownIcon } from './components/icon/ArrowDown.vue'; export { default as Input } from './components/Input.vue'; export { default as Clickoutside } from './directives/clickoutside.js'; export { default as Table } from './components/Table.vue'; From 30db493b37c343c3da04207493c657b3e02558bc Mon Sep 17 00:00:00 2001 From: fly_dream <1456207945@qq.com> Date: Fri, 7 Jun 2024 11:09:57 +0800 Subject: [PATCH 18/18] chore(main): release 0.5.4 (#16) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8254722..1e097dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.4](https://github.com/DvShu/neatui-vue/compare/v0.5.3...v0.5.4) (2024-06-07) + + +### Bug Fixes + +* 修复上个版本未正确导出组件 ([404aac0](https://github.com/DvShu/neatui-vue/commit/404aac00600084214276e9d38b29a267b1b5638c)) + ## [0.5.3](https://github.com/DvShu/neatui-vue/compare/v0.5.2...v0.5.3) (2024-06-07) diff --git a/package.json b/package.json index 7353b4dd..20a3b5aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asteres/neatui-vue", "description": "基于 Vue3 的 UI 组件库", - "version": "0.5.3", + "version": "0.5.4", "type": "module", "scripts": { "g:c": "node scripts/index.js template",