├── .eslintrc.js ├── .github └── workflows │ └── doc.yml ├── .gitignore ├── .npmignore ├── .prettierrc.js ├── .storybook ├── addons.js ├── babel-plugin-react-docgen │ ├── actualNameHandler.js │ └── index.js ├── babel.config.js ├── config.js ├── style.less └── webpack.config.js ├── .stylelintrc ├── .svgrrc.json ├── CHANGELOG.md ├── README.dev.md ├── README.md ├── babel.config.js ├── cropper ├── cropper.js ├── stories.js └── style.less ├── demo ├── demo │ ├── import.lead.js │ └── service_time.js └── doc │ ├── Cascader.md │ ├── CascaderSelect.md │ ├── Drawer.md │ ├── DropDown.md │ ├── DropSelect.md │ ├── FilterSearch.md │ ├── FilterSearchSelect.md │ ├── FilterSelect.md │ ├── ImagePreview.md │ ├── ImportLead.md │ ├── SearchSelect.md │ └── Validator.md ├── frame ├── breadcrumb.js ├── context.js ├── copyright.js ├── framework.js ├── framework.stories.js ├── full_tab.js ├── index.js ├── info.js ├── left.js ├── mobile.less ├── print.less ├── right_top.js └── style.less ├── i18n.config.js ├── keyboard ├── cell │ ├── cell_date_picker.js │ ├── cell_input.js │ ├── cell_input_number_v2.js │ ├── cell_level_select.js │ ├── cell_more_select.js │ ├── cell_select.js │ └── cell_table_select.js ├── core │ ├── cell.js │ ├── event.js │ ├── undo_manager.js │ ├── util.js │ └── wrap.js ├── for_table │ ├── keyboard_table_hoc.js │ └── keyboard_table_x_hoc.js ├── index.js ├── keyboard_table.stories.js └── keyboard_table_x.stories.js ├── locales ├── en.json ├── index.js ├── stories.js ├── th.json ├── zh-HK.json └── zh.json ├── package.json ├── postcss.config.js ├── sortable ├── base.js ├── index.js ├── js.stories.js ├── sortable.js ├── sortable.stories.js └── with.js ├── src ├── business │ └── manage_pagination │ │ ├── index.js │ │ ├── stories.js │ │ ├── transform.js │ │ └── v2.js ├── component │ ├── affix │ │ ├── affix.stories.js │ │ └── index.js │ ├── box │ │ ├── box.js │ │ ├── box.stories.js │ │ ├── box_form.js │ │ ├── box_panel.js │ │ ├── box_table.js │ │ ├── index.js │ │ └── style.less │ ├── button │ │ ├── button.stories.js │ │ ├── index.js │ │ └── style.less │ ├── calendar │ │ ├── calendar.js │ │ ├── calendar.stories.js │ │ ├── content.js │ │ ├── day.js │ │ ├── head.js │ │ ├── index.js │ │ ├── range_calendar.js │ │ ├── style.less │ │ └── week.js │ ├── carousel │ │ ├── carousel.js │ │ ├── stories.js │ │ └── style.less │ ├── cascader │ │ ├── cascader.js │ │ ├── cascader.select.js │ │ ├── stories.js │ │ └── style.less │ ├── checkbox │ │ ├── checkbox.js │ │ ├── checkbox_group.js │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── collapse │ │ ├── collapse.stories.js │ │ └── index.js │ ├── color_picker │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── date_picker │ │ ├── date_picker.stories.js │ │ └── index.js │ ├── date_range_picker │ │ ├── bottom.js │ │ ├── date_range_picker.stories.js │ │ ├── index.js │ │ ├── left.js │ │ ├── overlay.js │ │ ├── style.less │ │ ├── two.js │ │ └── util.js │ ├── dialog │ │ ├── index.js │ │ └── stories.js │ ├── divider │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── drawer │ │ ├── index.js │ │ └── style.less │ ├── drop_down │ │ ├── drop_down.js │ │ ├── drop_down_item.js │ │ ├── drop_down_items.js │ │ ├── index.js │ │ └── style.less │ ├── drop_select │ │ ├── index.js │ │ └── style.less │ ├── dropper │ │ ├── index.js │ │ └── style.less │ ├── editable_text │ │ ├── editable_text.stories.js │ │ ├── index.js │ │ └── style.less │ ├── filter_select │ │ ├── filter.select.js │ │ ├── multiple.filter.select.js │ │ └── style.less │ ├── flex │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── flip_number │ │ ├── index.js │ │ ├── stories.js │ │ └── utils.js │ ├── form │ │ ├── form.js │ │ ├── form.stories.js │ │ ├── form_block.js │ │ ├── form_button.js │ │ ├── form_group.js │ │ ├── form_item.js │ │ ├── form_panel.js │ │ ├── index.js │ │ ├── style.less │ │ └── util.js │ ├── function_set │ │ ├── function_set.stories.js │ │ ├── index.js │ │ └── overlay.js │ ├── grid │ │ ├── col.js │ │ ├── grid.stories.js │ │ ├── index.js │ │ ├── mixin.less │ │ ├── row.js │ │ ├── style.less │ │ └── util.js │ ├── icon_down_up │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── image_preview │ │ ├── index.js │ │ ├── preview_modal.js │ │ └── style.less │ ├── img_uploader │ │ ├── index.js │ │ ├── index.stories.js │ │ └── style.less │ ├── input │ │ └── index.js │ ├── input_number │ │ ├── index.js │ │ ├── number.js │ │ ├── stories.js │ │ └── style.less │ ├── layout_root │ │ └── index.js │ ├── lazy_img │ │ └── index.js │ ├── level_list │ │ ├── index.js │ │ ├── level_item.js │ │ ├── level_list.stories.js │ │ ├── style.less │ │ └── util.js │ ├── level_select │ │ ├── index.js │ │ └── level_select.stories.js │ ├── list │ │ ├── base.js │ │ ├── index.js │ │ ├── list.stories.js │ │ └── style.less │ ├── loading │ │ ├── index.js │ │ ├── loading_chunk.js │ │ ├── loading_full_screen.js │ │ ├── stories.js │ │ └── style.less │ ├── mask │ │ ├── index.js │ │ └── style.less │ ├── modal │ │ ├── clean_modal.js │ │ ├── index.js │ │ ├── right_side_modal.js │ │ ├── stories.js │ │ └── style.less │ ├── more_select │ │ ├── base.js │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── nav │ │ ├── index.js │ │ ├── nav.stories.js │ │ └── style.less │ ├── nprogress │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── pagination │ │ ├── base.js │ │ ├── left.js │ │ ├── page.js │ │ ├── page_peek.js │ │ ├── pagination.js │ │ ├── pagination.stories.js │ │ ├── pagination_text.js │ │ ├── pagination_v2.js │ │ ├── right.js │ │ ├── style.less │ │ └── util.js │ ├── popover │ │ ├── index.js │ │ └── stories.js │ ├── popup │ │ ├── index.js │ │ ├── popup.js │ │ ├── popup_content_confirm.js │ │ └── style.less │ ├── price │ │ ├── index.js │ │ └── stories.js │ ├── progress │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── progress_circle │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── radio │ │ ├── index.js │ │ ├── radio.js │ │ ├── radio_group.js │ │ ├── stories.js │ │ └── style.less │ ├── select │ │ ├── index.js │ │ ├── option.js │ │ ├── select.js │ │ ├── select.stories.js │ │ └── style.less │ ├── selection │ │ ├── index.js │ │ ├── selection.stories.js │ │ └── style.less │ ├── sheet │ │ ├── index.js │ │ ├── sheet.js │ │ ├── sheet_action.js │ │ ├── sheet_batch_action.js │ │ ├── sheet_column.js │ │ ├── sheet_select.js │ │ ├── stories.js │ │ └── style.less │ ├── steps │ │ ├── index.js │ │ ├── steps.stories.js │ │ └── style.less │ ├── storage │ │ ├── index.js │ │ └── stories.js │ ├── switch │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── table_select │ │ ├── index.js │ │ ├── style.less │ │ ├── table_select.stories.js │ │ └── util.js │ ├── tabs │ │ ├── style.less │ │ ├── tabs.js │ │ └── tabs.stories.js │ ├── time_span │ │ ├── style.less │ │ ├── time_span.js │ │ ├── time_span.stories.js │ │ ├── time_span_picker.js │ │ └── time_span_picker.stories.js │ ├── tip │ │ ├── index.js │ │ ├── stories.js │ │ └── style.less │ ├── tool_tip │ │ ├── index.js │ │ └── stories.js │ ├── transfer │ │ ├── box.js │ │ ├── index.js │ │ ├── stories.js │ │ ├── style.less │ │ ├── transfer.js │ │ └── transfer_group.js │ ├── tree │ │ ├── bottom.js │ │ ├── index.js │ │ ├── item.js │ │ ├── list.js │ │ ├── style.less │ │ ├── tree.stories.js │ │ └── util.js │ └── uploader │ │ ├── index.js │ │ ├── style.less │ │ └── uploader.stories.js ├── css │ ├── animation.less │ ├── arrow.less │ ├── bg.less │ ├── border.less │ ├── cover.less │ ├── cursor.less │ ├── display.less │ ├── distance.less │ ├── error.less │ ├── overflow.less │ ├── position.less │ ├── rotate.less │ ├── shadow.less │ ├── stories.js │ ├── svg.less │ ├── text.less │ └── variables.less ├── demo.stories.js ├── deprecated │ ├── import_lead │ │ ├── index.js │ │ └── style.less │ ├── pagination_fuck │ │ └── pagination_fuck.js │ ├── quick │ │ ├── index.js │ │ ├── quick_desc.js │ │ ├── quick_detail.js │ │ ├── quick_filter.js │ │ ├── quick_panel.js │ │ ├── quick_tab.js │ │ └── style.less │ ├── search_select │ │ ├── filter.search.select.js │ │ ├── search.select.js │ │ └── style.less │ ├── tree_select │ │ ├── index.js │ │ └── style.less │ └── trigger │ │ ├── index.js │ │ └── style.less ├── event_type.js ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── index.js ├── index.less ├── less │ ├── .csscomb.json │ ├── .csslintrc │ ├── alerts.less │ ├── badges.less │ ├── bootstrap.less │ ├── breadcrumbs.less │ ├── button-groups.less │ ├── buttons.less │ ├── carousel.less │ ├── close.less │ ├── code.less │ ├── component-animations.less │ ├── custom.less │ ├── dropdowns.less │ ├── forms.less │ ├── glyphicons.less │ ├── grid.less │ ├── input-groups.less │ ├── jumbotron.less │ ├── labels.less │ ├── list-group.less │ ├── media.less │ ├── mixins.less │ ├── mixins │ │ ├── alerts.less │ │ ├── background-variant.less │ │ ├── border-radius.less │ │ ├── buttons.less │ │ ├── center-block.less │ │ ├── clearfix.less │ │ ├── forms.less │ │ ├── gradients.less │ │ ├── grid-framework.less │ │ ├── grid.less │ │ ├── hide-text.less │ │ ├── image.less │ │ ├── labels.less │ │ ├── list-group.less │ │ ├── nav-divider.less │ │ ├── nav-vertical-align.less │ │ ├── opacity.less │ │ ├── pagination.less │ │ ├── panels.less │ │ ├── progress-bar.less │ │ ├── reset-filter.less │ │ ├── reset-text.less │ │ ├── resize.less │ │ ├── responsive-visibility.less │ │ ├── size.less │ │ ├── tab-focus.less │ │ ├── table-row.less │ │ ├── text-emphasis.less │ │ ├── text-overflow.less │ │ └── vendor-prefixes.less │ ├── modals.less │ ├── navbar.less │ ├── navs.less │ ├── normalize.less │ ├── pager.less │ ├── pagination.less │ ├── panels.less │ ├── popovers.less │ ├── print.less │ ├── progress-bars.less │ ├── responsive-embed.less │ ├── responsive-utilities.less │ ├── scaffolding.less │ ├── tables.less │ ├── theme.less │ ├── thumbnails.less │ ├── tooltip.less │ ├── type.less │ ├── utilities.less │ ├── variables.less │ └── wells.less ├── locales.js ├── locales │ └── lng │ │ └── zh.json ├── other.less ├── sotries.js ├── util.js ├── validator │ ├── index.js │ ├── rules.js │ ├── type.js │ └── validator.js └── var.less ├── svg ├── calendar-month.svg ├── calendar-year.svg ├── calendar.svg ├── check-detail.svg ├── close-circle.svg ├── closeup.svg ├── delete.svg ├── down-small.svg ├── down.svg ├── edit-box.svg ├── edit-pen.svg ├── edit.svg ├── empty.svg ├── expand.svg ├── fun.svg ├── info-circle-o.svg ├── left-small.svg ├── minus-square.svg ├── minus.svg ├── more.svg ├── next.svg ├── ok.svg ├── pen.svg ├── plus-square.svg ├── plus.svg ├── question-circle-o.svg ├── remove.svg ├── right-small.svg ├── setting.svg ├── success-circle-o.svg ├── success-circle.svg ├── up-small.svg ├── up.svg └── warning-circle-o.svg ├── table ├── cell.less ├── dnd_table.js ├── edit │ ├── edit_table.js │ └── edit_table.stories.js ├── hoc │ ├── diy_table │ │ ├── diy_table_modal.js │ │ ├── index.js │ │ ├── selector.js │ │ └── sort_list.js │ ├── expand_table.js │ ├── fixed_columns_table.js │ ├── fixed_first_columns_table.js │ ├── select_table │ │ ├── batch_action_bar.js │ │ ├── index.js │ │ └── select_table_base.js │ ├── sub_table.js │ └── table_hoc.stories.js ├── index.js ├── style.less ├── table │ ├── base.js │ ├── index.js │ └── table.stories.js ├── table_util.stories.js └── util.js ├── table_x ├── README.md ├── base │ ├── index.js │ ├── td.js │ ├── th.js │ ├── thead.js │ ├── tr.js │ └── virtualized.js ├── hoc │ ├── diy_table_x │ │ ├── components │ │ │ ├── diy_table_x_modal.js │ │ │ ├── modal_list.js │ │ │ └── modal_selector.js │ │ └── index.js │ ├── edit_table_x.js │ ├── expand_table_x.js │ ├── fixed_columns_table_x.js │ ├── select_table_x.js │ ├── sortable_table_x.js │ └── sub_table_x.js ├── index.js ├── stories │ ├── table_x.stories.js │ ├── table_x_hoc.stories.js │ └── table_x_hoc_select_expand.stories.js ├── style.less ├── util │ ├── edit.js │ ├── index.js │ ├── operation.js │ └── sort_header.js └── variables.less └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': [ 3 | 'plugin:gmfe/recommended' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | name: doc 2 | 3 | # event type(此处我们选择 push,且仅当 push 到 master 分支触发) 4 | on: 5 | push: 6 | branches: 7 | - master 8 | - feature-actions 9 | 10 | # 任务列表 11 | jobs: 12 | # 任务名称 13 | release: 14 | # 在何种平台执行,可选 windows-latest/ubuntu-latest/macOS-latest 等 15 | runs-on: ubuntu-latest 16 | 17 | # 为了加速构建,我们使用同一个包含 Node.js 的容器运行所有命令 18 | container: 19 | image: thonatos/github-actions-nodejs 20 | 21 | # 这里定义了任务运行过程中的各个步骤 22 | steps: 23 | # 环境 24 | - run: | 25 | npm -v 26 | node -v 27 | yarn -v 28 | git config --global user.email "actions@github.com" 29 | git config --global user.name "actions" 30 | 31 | - run: | 32 | pwd 33 | git clone https://github.com/gmfe/react-gm.git 34 | cd react-gm 35 | 36 | yarn 37 | npm run build 38 | ls | grep -v docs | xargs rm -rf 39 | rm -rf .github && rm -rf .storybook 40 | git add --all 41 | git commit -m 'build docs' 42 | 43 | pwd 44 | git push 'https://liyatang%40qq.com:${{secrets.PASSWORD}}@github.com/gmfe/react-gm-docs.git' master:master -f 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | npm-debug.log 4 | node_modules/ 5 | .stylelintcache 6 | .eslintcache 7 | yarn-error.log 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | npm-debug.log 4 | yarn.lock 5 | /demo 6 | /docs 7 | .stylelintcache 8 | .eslintcache 9 | yarn-error.log 10 | 11 | 12 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | singleQuote: true, 4 | jsxSingleQuote: true 5 | } 6 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-storysource/register' 2 | -------------------------------------------------------------------------------- /.storybook/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = api => { 2 | api.cache(true) 3 | return { 4 | ignore: [/@babel[/\\]runtime/], // 忽略 @babel/runtime 5 | presets: ['gmfe'] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.storybook/style.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/.storybook/style.less -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard" 3 | } -------------------------------------------------------------------------------- /.svgrrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": true, 3 | "expandProps": "start", 4 | "svgProps": { 5 | "fill": "currentColor", 6 | "className": "{'gm-svg-icon ' + (props.className || '')}" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 9.x 2 | 3 | ## breaking changes 4 | 5 | ### component 6 | 7 | Framework 不内嵌 LayoutRoot,调用方自行放 LayoutRoot 位置 8 | Breadcrumb 改了 9 | Info 改了 10 | FullTab 改了 11 | 12 | 移除 Menu 13 | 14 | Calendar 15 | DatePicker props 和 UI 有变动,请查阅 16 | DateRangePicker props 和 UI 有变动,请查阅 17 | 18 | Form 大改 19 | Nav 改了 20 | Pagination toPage 移除第一个参数。(扫了 station,没人用) 21 | 22 | PaginationNew => PaginationFuck 23 | 24 | PaginationBox 25 | - => ManagePaginationV2 26 | - doCurrentPageRequest => doCurrentRequest 27 | - limit => defaultLimit 28 | 29 | ### Table 30 | 31 | 引用库 react-table 6.x 切到 react-table-v6。 32 | 33 | - selectTableV2HOC props 移除了 `selectAll` 和 `selectAllTip`,增加了 `batchActionBar` 34 | 35 | - diyTableHOC 移除了 `ref.apiToggleDiySelector`, props `columns` 要求增加多个参数, `diyGroupNameSorting`等 36 | 37 | - selectTableHOC SelectTable 移除 38 | 39 | - 默认没有top, left, right 的border 40 | 41 | ### css 42 | 43 | 移除 .ifont- .xfont- 等功能性样式,替换为 .gm-svg-icon 44 | 45 | # 8.x 46 | 47 | ## breaking changes 48 | 49 | remove Emitter 50 | 51 | remove src/framework 52 | 53 | List 的 data 改为 [{value, text}] ,renderName 改为 renderItem 54 | remove ListGroup,统统在 List 里 55 | 56 | -------------------------------------------------------------------------------- /README.dev.md: -------------------------------------------------------------------------------- 1 | # 开发文档 2 | 3 | ## z-index层级管理 4 | 5 | ### 布局流 6 | 7 | - chunk loading 90 8 | - header 100 9 | - trigger popup 900 10 | - nav 910 11 | - sticky 950 12 | 13 | ### 浮层 14 | 15 | - mask 1000 16 | - drawer 1030 drawer_mask 1020 17 | - modal 1050 modal mask 1040 18 | - popup 2000 19 | - tip 7000 20 | - full_screen loading 8000 21 | - nprogress 9999 22 | 23 | 待整理 24 | 25 | - drop_select 1000 26 | 27 | ## 组件规范 28 | 29 | 重要 props 放上面 30 | props children 不写 31 | 尽量使用 docgen 描述组件 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm](https://img.shields.io/npm/v/react-gm.svg)](https://www.npmjs.com/package/react-gm) [![Actions Status](https://github.com/gmfe/react-gm/workflows/doc/badge.svg)](https://github.com/{owner}/{repo}/actions) 2 | 3 | [![JavaScript Style Guide](https://cdn.rawgit.com/standard/standard/master/badge.svg)](https://github.com/standard/standard) 4 | 5 | ## About react-gm 6 | 7 | 愿景:致力于快速搭建项目,像搭积木一样。 8 | 9 | 为什么叫 gm,因为就职于 观麦。我更喜欢定义为 Get More More Growth。 10 | 11 | [文档 and demo](http://gmfe.github.io/react-gm/) 12 | 13 | ## Install 14 | 15 | `npm install react-gm -D` 16 | 17 | ## 依赖 18 | 19 | 使用前请保证以下依赖存在 20 | - react 21 | - react-dom 22 | - @svgr/webpack 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = api => { 2 | api.cache(true) 3 | return { 4 | ignore: [/@babel[/\\]runtime/], // 忽略 @babel/runtime 5 | presets: ['gmfe'] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cropper/style.less: -------------------------------------------------------------------------------- 1 | @import '../node_modules/cropperjs/dist/cropper.css'; 2 | 3 | .gm-cropper { 4 | width: 500px; 5 | 6 | .gm-cropper-img { 7 | display: block; 8 | width: 360px; 9 | height: 360px; 10 | max-width: 360px; 11 | max-height: 360px; 12 | } 13 | 14 | .gm-cropper-preview { 15 | width: 120px; 16 | max-width: 120px; 17 | height: 120px; 18 | max-height: 120px; 19 | overflow: hidden; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/doc/Drawer.md: -------------------------------------------------------------------------------- 1 | --- 2 | imports: 3 | import {Drawer, Dialog} from '../../src/index'; 4 | 5 | --- 6 | ## Drawer 7 | 背景: `Drawer`的出现,是为了在Drawer之上再次弹出浮层,例如Dialog 8 | 9 | ::: demo Drawer 10 | ```js 11 | class ModalWrap extends React.Component { 12 | handleModal(){ 13 | Drawer.render({ 14 | children:
15 |
16 | {Array(100).fill(
一行
)} 17 |
18 |
{ 19 | Dialog.confirm({ 20 | children: '我是Dialog' 21 | }).then(() => { 22 | Drawer.hide() 23 | }) 24 | }}>弹出Dialog
25 | 26 | 27 | 28 |
, 29 | onHide: Drawer.hide, 30 | opacityMask: true, 31 | style: {width: '600px', height: '100%'}} 32 | ); 33 | } 34 | 35 | render() { 36 | return ( 37 |
38 | 43 |
); 44 | } 45 | } 46 | ``` 47 | ```jsx 48 | 49 | ``` 50 | ::: 51 | 52 | 53 | ### Props 54 | - `onHide (func)` 隐藏触发回调 55 | - `opacityMask (bool)` 遮罩透明 56 | - `children` 抽屉内容 57 | - `style (object)` drawer的样式 58 | - `animation (bool)` 是否使用动画, 默认为ture 59 | 60 | ### Static 61 | - `render` 62 | - `hide` 63 | -------------------------------------------------------------------------------- /demo/doc/ImportLead.md: -------------------------------------------------------------------------------- 1 | --- 2 | imports: 3 | import {ImportLead} from '../../src/index'; 4 | --- 5 | ## ImportLead 6 | 7 | ::: demo 指引 8 | ```js 9 | class Component extends React.Component { 10 | render() { 11 | return ( 12 |
13 | lalala 14 |
15 | ); 16 | } 17 | } 18 | ``` 19 | ```jsx 20 | 21 | ``` 22 | ::: 23 | 24 | ### Props 25 | // TODO 26 | - `data`: PropTypes.object, 27 | - `tips`: PropTypes.array, 28 | - `onEdit`: PropTypes.func, 29 | - `fileTempUrl`: PropTypes.string, 30 | - `disableEdit`: PropTypes.bool, 31 | - `unLine`: PropTypes.bool, 32 | - `disableSubmit`: PropTypes.bool -------------------------------------------------------------------------------- /demo/doc/Validator.md: -------------------------------------------------------------------------------- 1 | --- 2 | imports: 3 | import {Validator} from '../../src/index'; 4 | --- 5 | ## Validator 6 | 7 | 三个方法 8 | - `register` 注册校验类型,内置有部分,具体看rules.js文件 9 | - `validate` 校验。成功返回空字符串,校验不通过返回帮助信息 10 | - `create` 创建校验函数,配合`FormItem`使用。 参数types 可以是具体的校验类型,或者校验类型集合 11 | 12 | demo 见[Form](#/doc/Form) 13 | -------------------------------------------------------------------------------- /frame/context.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Context = React.createContext() 4 | 5 | export default Context 6 | -------------------------------------------------------------------------------- /frame/copyright.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex } from '../src/index' 3 | 4 | const Copyright = () => ( 5 | 11 | 深圳市观麦网络科技有限公司 Copyright©2013-2017 12 | 20 |  粤ICP备14066539号-2 21 | 22 | 23 | ) 24 | 25 | export default Copyright 26 | -------------------------------------------------------------------------------- /frame/framework.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { Framework, RightTop, Info, FullTab } from './index' 4 | 5 | storiesOf('框架|FrameWork', module).add('default', () => ( 6 |
7 | 13 | adfafa 14 |
15 | } 16 | rightTop={ 17 | { 24 | console.log('123') 25 | } 26 | } 27 | ]} 28 | /> 29 | } 30 | /> 31 | } 32 | > 33 | 34 |
按订单查看
35 |
按商品查看
36 |
37 | 38 | 39 | )) 40 | -------------------------------------------------------------------------------- /frame/index.js: -------------------------------------------------------------------------------- 1 | import Framework from './framework' 2 | import CopyRight from './copyright' 3 | import Info from './info' 4 | import Breadcrumb from './breadcrumb' 5 | import Left from './left' 6 | import RightTop from './right_top' 7 | import FullTab from './full_tab' 8 | 9 | export { Framework, Left, RightTop, CopyRight, Info, Breadcrumb, FullTab } 10 | -------------------------------------------------------------------------------- /frame/info.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Flex, Popover, List } from '../src/index' 4 | import _ from 'lodash' 5 | import SVGMore from '../svg/more.svg' 6 | 7 | const Info = props => { 8 | const { more, children } = props 9 | 10 | const listData = _.map(more, (v, i) => ({ value: i, text: v.text })) 11 | 12 | const handleSelect = value => { 13 | more[value].onClick() 14 | } 15 | 16 | return ( 17 | 18 | 19 | {children} 20 | {more && ( 21 | 33 | } 34 | > 35 |
36 | 37 |
38 |
39 | )} 40 |
41 | ) 42 | } 43 | 44 | Info.propTypes = { 45 | more: PropTypes.array // [{text, onClick}] 46 | } 47 | 48 | export default Info 49 | -------------------------------------------------------------------------------- /frame/left.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | import Context from './context' 5 | 6 | const Left = props => { 7 | const { style, className, children, ...rest } = props 8 | const { leftWidth } = React.useContext(Context) 9 | 10 | return ( 11 |
16 |
{children}
17 |
18 | ) 19 | } 20 | 21 | Left.propTypes = { 22 | style: PropTypes.object, 23 | className: PropTypes.string 24 | } 25 | 26 | export default Left 27 | -------------------------------------------------------------------------------- /frame/mobile.less: -------------------------------------------------------------------------------- 1 | @media (max-width: 768px) { 2 | .gm-framework { 3 | &-left { 4 | &-default { 5 | width: 0 !important; 6 | 7 | &-inner { 8 | left: -110%; 9 | } 10 | } 11 | } 12 | 13 | &-right-top { 14 | &-default { 15 | &-inner { 16 | left: 0 !important; 17 | 18 | .gm-framework-right-top-default-mobile-nav { 19 | display: block; 20 | } 21 | } 22 | } 23 | } 24 | 25 | &.gm-framework-mobile-menu { 26 | .gm-framework-left-default-inner { 27 | left: 0; 28 | width: 100vw !important; 29 | } 30 | } 31 | 32 | .gm-framework-full-tabs { 33 | .gm-framework-full-tabs-list { 34 | left: 0 !important; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /frame/print.less: -------------------------------------------------------------------------------- 1 | @media print { 2 | html, 3 | body { 4 | background-color: white; 5 | } 6 | 7 | // 本身 打印 页面就小,命中了 framework/mobile.less 把相应的UI去掉了,但 8 | // 1 毕竟属于两种场景 9 | // 2 可能存在大的打印纸张 10 | // 所以还是要处理一遍 11 | .gm-framework { 12 | &-full-height { 13 | min-height: inherit; 14 | } 15 | 16 | &-left { 17 | display: none; 18 | } 19 | 20 | &-right-top { 21 | display: none; 22 | } 23 | 24 | &-content { 25 | padding: 0; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /frame/right_top.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Flex } from '../src/index' 4 | import _ from 'lodash' 5 | import Context from './context' 6 | 7 | const RightTop = props => { 8 | const { breadcrumb, onMenuBtnClick, info } = props 9 | const { leftWidth } = React.useContext(Context) 10 | 11 | return ( 12 |
13 | 18 | onMenuBtnClick()} 22 | > 23 | 24 | 25 | 26 | {breadcrumb} 27 | 28 |
{info}
29 |
30 |
31 | ) 32 | } 33 | 34 | RightTop.propTypes = { 35 | breadcrumb: PropTypes.element, 36 | info: PropTypes.element, 37 | onMenuBtnClick: PropTypes.func 38 | } 39 | 40 | RightTop.defaultProps = { 41 | onMenuBtnClick: _.noop 42 | } 43 | 44 | export default RightTop 45 | -------------------------------------------------------------------------------- /i18n.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | callStatement: 'getLocale', 3 | importStatementStr: "import { getLocale } from '../../locales'\n", 4 | exclude: ['price/index.js', '**/*.stories.js'] 5 | } 6 | -------------------------------------------------------------------------------- /keyboard/core/event.js: -------------------------------------------------------------------------------- 1 | const KEYBOARD_ONFOCUS = 'KEYBOARD_ONFOCUS_' 2 | const KEYBOARD_DIRECTION = 'KEYBOARD_DIRECTION_' 3 | const KEYBOARD_ENTER = 'KEYBOARD_ENTER_' 4 | const KEYBOARD_TAB = 'KEYBOARD_TAB_' 5 | 6 | export { KEYBOARD_ONFOCUS, KEYBOARD_DIRECTION, KEYBOARD_ENTER, KEYBOARD_TAB } 7 | -------------------------------------------------------------------------------- /keyboard/index.js: -------------------------------------------------------------------------------- 1 | import keyboardTableHoc from './for_table/keyboard_table_hoc' 2 | import keyboardTableXHOC from './for_table/keyboard_table_x_hoc' 3 | import KC from './core/cell' 4 | import KCInput from './cell/cell_input' 5 | import KCMoreSelect from './cell/cell_more_select' 6 | import KCInputNumberV2 from './cell/cell_input_number_v2' 7 | import KCLevelSelect from './cell/cell_level_select' 8 | import KCTableSelect from './cell/cell_table_select' 9 | import KCDatePicker from './cell/cell_date_picker' 10 | import KCSelect from './cell/cell_select' 11 | import { 12 | isInputUnBoundary, 13 | scrollIntoViewFixedWidth, 14 | doFocus 15 | } from './core/util' 16 | 17 | // 只暴露写方法 18 | const KeyboardUtil = { 19 | isInputUnBoundary, 20 | scrollIntoViewFixedWidth, 21 | doFocus 22 | } 23 | 24 | export { 25 | keyboardTableHoc, 26 | keyboardTableXHOC, 27 | KC, 28 | KCInput, 29 | KCInputNumberV2, 30 | KCMoreSelect, 31 | KCLevelSelect, 32 | KCTableSelect, 33 | KCDatePicker, 34 | KCSelect, 35 | KeyboardUtil 36 | } 37 | -------------------------------------------------------------------------------- /locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "1月": "Jan", 3 | "2月": "Feb", 4 | "3月": "Mar", 5 | "4月": "Apr", 6 | "5月": "May", 7 | "6月": "Jun", 8 | "7月": "Jul", 9 | "8月": "Aug", 10 | "9月": "Sep", 11 | "10月": "Oct", 12 | "11月": "Nov", 13 | "12月": "Dec", 14 | "week__日": "Su", 15 | "week__一": "Mo", 16 | "week__二": "Tu", 17 | "week__三": "We", 18 | "week__四": "Th", 19 | "week__五": "Fr", 20 | "week__六": "Sa", 21 | "提示": "Tips", 22 | "取消": "Cancel", 23 | "确定": "OK", 24 | "操作": "Operation", 25 | "保存": "Save", 26 | "确认": "OK", 27 | "没有更多数据了": "No data here", 28 | "上一页": "Previous", 29 | "下一页": "Next", 30 | "显示": "Show", 31 | "共": "A total of", 32 | "条": " ", 33 | "收拢详细信息": "Collapse details", 34 | "展开详细信息": "Expand details", 35 | "已选中所有": "", 36 | "全选": "Select all", 37 | "待选择": "ItemsSource", 38 | "搜索": "Search", 39 | "已选择": "Target", 40 | "请填写": "Please enter", 41 | "请填写邮件地址": "Please enter email address", 42 | "请填写网址": "Please enter URL", 43 | "请填写数字": "Please enter number", 44 | "请填写正数": "Please enter positive number", 45 | "请填写字母或数字": "Please enter number or letter", 46 | "表头设置": "Table header setting", 47 | "勾选当前页内容": "Check the current page", 48 | "勾选所有页内容": "Check all page content", 49 | "项": "items" 50 | } 51 | -------------------------------------------------------------------------------- /locales/index.js: -------------------------------------------------------------------------------- 1 | /* 此文件由脚本自动生成 */ 2 | import lng1 from './zh.json' 3 | import lng2 from './zh-HK.json' 4 | import lng3 from './en.json' 5 | import lng4 from './th.json' 6 | const moduleMap = { 7 | zh: lng1, 8 | 'zh-HK': lng2, 9 | en: lng3, 10 | th: lng4 11 | } 12 | let _language = 'zh' 13 | 14 | const setLocale = lng => { 15 | _language = lng 16 | } 17 | 18 | const getLocale = text => { 19 | const languageMap = moduleMap[_language] || moduleMap['zh'] 20 | let result = languageMap[text] 21 | 22 | if (!result) { 23 | result = text.split('__').pop() 24 | } 25 | 26 | return result 27 | } 28 | 29 | export { getLocale, setLocale } 30 | -------------------------------------------------------------------------------- /locales/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { setLocale } from './index' 4 | import { Storage } from '../src' 5 | import { observable } from 'mobx' 6 | 7 | const store = observable({ 8 | lng: Storage.get('lng') || 'zh' 9 | }) 10 | 11 | storiesOf('locale', module).add('default', () => ( 12 | 24 | )) 25 | -------------------------------------------------------------------------------- /locales/th.json: -------------------------------------------------------------------------------- 1 | { 2 | "1月": "", 3 | "2月": "", 4 | "3月": "", 5 | "4月": "", 6 | "5月": "", 7 | "6月": "", 8 | "7月": "", 9 | "8月": "", 10 | "9月": "", 11 | "10月": "", 12 | "11月": "", 13 | "12月": "", 14 | "week__日": "", 15 | "week__一": "", 16 | "week__二": "", 17 | "week__三": "", 18 | "week__四": "", 19 | "week__五": "", 20 | "week__六": "", 21 | "提示": "", 22 | "取消": "", 23 | "确定": "", 24 | "操作": "", 25 | "保存": "", 26 | "确认": "", 27 | "没有数据": "", 28 | "上一页": "", 29 | "下一页": "", 30 | "显示": "", 31 | "共": "", 32 | "条": "", 33 | "收拢详细信息": "", 34 | "展开详细信息": "", 35 | "已选中所有": "", 36 | "全选": "", 37 | "待选择": "", 38 | "搜索": "", 39 | "已选择": "", 40 | "请填写": "", 41 | "请填写邮件地址": "", 42 | "请填写网址": "", 43 | "请填写数字": "", 44 | "请填写正数": "", 45 | "请填写字母或数字": "" 46 | } 47 | -------------------------------------------------------------------------------- /locales/zh-HK.json: -------------------------------------------------------------------------------- 1 | { 2 | "1月": "1月", 3 | "2月": "2月", 4 | "3月": "3月", 5 | "4月": "4月", 6 | "5月": "5月", 7 | "6月": "6月", 8 | "7月": "7月", 9 | "8月": "8月", 10 | "9月": "9月", 11 | "10月": "10月", 12 | "11月": "11月", 13 | "12月": "12月", 14 | "week__日": "日", 15 | "week__一": "一", 16 | "week__二": "二", 17 | "week__三": "三", 18 | "week__四": "四", 19 | "week__五": "五", 20 | "week__六": "六", 21 | "提示": "提示", 22 | "取消": "取消", 23 | "确定": "確定", 24 | "操作": "操作", 25 | "保存": "保存", 26 | "确认": "確認", 27 | "没有更多数据了": "沒有更多數據了", 28 | "上一页": "上一頁", 29 | "下一页": "下一頁", 30 | "显示": "顯示", 31 | "共": "共", 32 | "条": "條", 33 | "收拢详细信息": "收攏詳細信息", 34 | "展开详细信息": "展開詳細信息", 35 | "已选中所有": "已選中所有", 36 | "全选": "全選", 37 | "待选择": "待選擇", 38 | "搜索": "搜索", 39 | "已选择": "已選擇", 40 | "请填写": "請填寫", 41 | "请填写邮件地址": "請填寫郵件地址", 42 | "请填写网址": "請填寫網址", 43 | "请填写数字": "請填寫數字", 44 | "请填写正数": "請填寫正數", 45 | "请填写字母或数字": "請填寫字母或數字" 46 | } 47 | -------------------------------------------------------------------------------- /locales/zh.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require('autoprefixer'), require('precss')] 3 | } 4 | -------------------------------------------------------------------------------- /sortable/index.js: -------------------------------------------------------------------------------- 1 | import Sortable from './sortable' 2 | import SortableBase from './base' 3 | 4 | export { Sortable, SortableBase } 5 | -------------------------------------------------------------------------------- /sortable/sortable.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import SortableBase from './base' 4 | import _ from 'lodash' 5 | import classNames from 'classnames' 6 | 7 | const Sortable = ({ 8 | data, 9 | onChange, 10 | renderItem, 11 | tag, 12 | options = {}, 13 | ...rest 14 | }) => { 15 | const handleChange = order => { 16 | order = _.map(order, v => JSON.parse(v)) 17 | const newData = _.sortBy(data.slice(), v => order.indexOf(v.value)) 18 | onChange(newData) 19 | } 20 | 21 | const items = _.map(data, (v, index) => ( 22 |
29 | {renderItem(v, index)} 30 |
31 | )) 32 | 33 | return ( 34 | 43 | {items} 44 | 45 | ) 46 | } 47 | 48 | Sortable.propTypes = { 49 | /** [{value, text, ...}, {value, text, ...}] */ 50 | data: PropTypes.array.isRequired, 51 | onChange: PropTypes.func.isRequired, 52 | renderItem: PropTypes.func, 53 | /** 支持 ref */ 54 | tag: PropTypes.node, 55 | options: PropTypes.object 56 | } 57 | 58 | Sortable.defaultProps = { 59 | renderItem: item => item.text 60 | } 61 | 62 | export default Sortable 63 | -------------------------------------------------------------------------------- /sortable/with.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 约定 Component 的子元素 存在 data-id */ 4 | const withSortable = Component => { 5 | return props => 6 | } 7 | 8 | export default withSortable 9 | -------------------------------------------------------------------------------- /src/business/manage_pagination/transform.js: -------------------------------------------------------------------------------- 1 | import PaginationBase from '../../component/pagination/base' 2 | import PropTypes from 'prop-types' 3 | import React from 'react' 4 | 5 | const Transform = ({ count, limit, currentIndex, peek, more, onChange }) => { 6 | const handleChange = ({ offset, limit }) => { 7 | onChange({ 8 | limit, 9 | currentIndex: offset / limit 10 | }) 11 | } 12 | 13 | let newCount = count 14 | if (count === undefined || count === null) { 15 | if (peek) { 16 | newCount = currentIndex * limit + peek 17 | } else { 18 | newCount = 0 19 | } 20 | } 21 | 22 | const _peekInfo = !count 23 | ? { 24 | peek, 25 | more 26 | } 27 | : undefined 28 | 29 | return ( 30 | 40 | ) 41 | } 42 | 43 | Transform.propTypes = { 44 | limit: PropTypes.number.isRequired, 45 | currentIndex: PropTypes.number.isRequired, 46 | count: PropTypes.number, 47 | peek: PropTypes.number, 48 | more: PropTypes.bool, 49 | onChange: PropTypes.func.isRequired 50 | } 51 | 52 | export default Transform 53 | -------------------------------------------------------------------------------- /src/component/affix/affix.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Affix from './index' 4 | 5 | storiesOf('Affix', module).add('default', () => ( 6 |
7 |
8 | 9 |
我会被钉住在底部 和 顶部
10 |
11 |
12 |
13 | )) 14 | -------------------------------------------------------------------------------- /src/component/affix/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Affix = ({ children, top, bottom }) => { 5 | const style = { 6 | position: 'sticky', 7 | bottom: bottom !== undefined ? `${bottom}px` : null, 8 | top: top !== undefined ? `${top}px` : null, 9 | zIndex: 950 10 | } 11 | 12 | return
{children}
13 | } 14 | 15 | Affix.propTypes = { 16 | children: PropTypes.any, 17 | top: PropTypes.number, 18 | bottom: PropTypes.number 19 | } 20 | 21 | export default Affix 22 | -------------------------------------------------------------------------------- /src/component/box/box.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | /** Box,用来包裹一块内容 */ 6 | const Box = props => { 7 | const { hasGap, className, children, ...rest } = props 8 | 9 | return ( 10 |
20 | {children} 21 |
22 | ) 23 | } 24 | 25 | Box.propTypes = { 26 | hasGap: PropTypes.bool, 27 | className: PropTypes.string, 28 | style: PropTypes.object 29 | } 30 | 31 | export default Box 32 | -------------------------------------------------------------------------------- /src/component/box/box_form.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Form } from '../form' 3 | import Flex from '../flex' 4 | import IconDownUp from '../icon_down_up' 5 | 6 | const BoxFormContext = React.createContext({ 7 | open: false 8 | }) 9 | 10 | const More = props => { 11 | return ( 12 | 13 | {({ open }) => { 14 | if (!open) { 15 | return null 16 | } 17 | return props.children 18 | }} 19 | 20 | ) 21 | } 22 | 23 | const BoxForm = props => { 24 | const [open, setOpen] = useState(false) 25 | 26 | const handleToggle = () => { 27 | setOpen(!open) 28 | } 29 | 30 | return ( 31 |
32 | 33 | 34 | 39 |
40 | {props.children} 41 |
42 |
43 |
44 | 50 |
51 |
52 | ) 53 | } 54 | 55 | BoxForm.More = More 56 | 57 | BoxForm.propTypes = { 58 | ...Form.propTypes 59 | } 60 | 61 | export default BoxForm 62 | -------------------------------------------------------------------------------- /src/component/box/box_table.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | import Flex from '../flex' 5 | 6 | // 暂时没什么用 7 | const Info = props => { 8 | return ( 9 |
13 | ) 14 | } 15 | 16 | Info.propTypes = { 17 | className: PropTypes.string, 18 | style: PropTypes.object 19 | } 20 | 21 | const BoxTable = props => { 22 | const { info, action, children, className, headerProps = {}, ...rest } = props 23 | const { className: headerClassName } = headerProps 24 | 25 | return ( 26 |
27 | 32 | {info} 33 | 34 | {action} 35 | 36 |
{children}
37 |
38 | ) 39 | } 40 | 41 | BoxTable.Info = Info 42 | 43 | BoxTable.propTypes = { 44 | info: PropTypes.element, 45 | action: PropTypes.element, 46 | className: PropTypes.string, 47 | style: PropTypes.object, 48 | headerProps: PropTypes.object 49 | } 50 | 51 | export default BoxTable 52 | -------------------------------------------------------------------------------- /src/component/box/index.js: -------------------------------------------------------------------------------- 1 | import Box from './box' 2 | import BoxForm from './box_form' 3 | import BoxTable from './box_table' 4 | import BoxPanel from './box_panel' 5 | 6 | export { Box, BoxForm, BoxTable, BoxPanel } 7 | -------------------------------------------------------------------------------- /src/component/box/style.less: -------------------------------------------------------------------------------- 1 | .gm-box { 2 | background: white; 3 | 4 | & + .gm-box { 5 | border-top: 1px solid fadeout(@gm-frame-border-color, 50%); 6 | } 7 | 8 | &.gm-box-table { 9 | .gm-box-table-header { 10 | padding: 10px 20px; 11 | height: 50px; 12 | background-color: @gm-back-body-bg; 13 | } 14 | } 15 | 16 | &.gm-box-form { 17 | padding: 10px 20px; 18 | } 19 | 20 | &.gm-box-panel { 21 | padding: 20px 0 0 0; 22 | 23 | .gm-box-panel-header { 24 | margin: 0 0 15px; 25 | padding: 0 20px; 26 | 27 | .gm-box-panel-title { 28 | font-size: 14px; 29 | padding-left: 10px; 30 | } 31 | 32 | .gm-box-panel-summary { 33 | border-left: 1px solid @gm-frame-border-color; 34 | margin-left: 10px; 35 | padding-left: 10px; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/component/button/style.less: -------------------------------------------------------------------------------- 1 | .gm-button { 2 | .gm-button-loading { 3 | display: inline-block; 4 | animation: gm-rotating 1s linear infinite; 5 | } 6 | } 7 | 8 | @keyframes gm-rotating { 9 | 0% { 10 | transform: rotate(0); 11 | } 12 | 13 | 100% { 14 | transform: rotate(360deg); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/component/calendar/calendar.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import RangeCalendar from './range_calendar' 3 | import PropTypes from 'prop-types' 4 | import _ from 'lodash' 5 | 6 | const Calendar = props => { 7 | const { selected, onSelect, ...rest } = props 8 | 9 | const handleSelect = begin => { 10 | onSelect(begin) 11 | } 12 | 13 | return ( 14 | 21 | ) 22 | } 23 | 24 | Calendar.propTypes = { 25 | /** 日期,Date 对象 */ 26 | selected: PropTypes.object, 27 | /** 日期选中回调函数,参数 date */ 28 | onSelect: PropTypes.func, 29 | /** 键盘 */ 30 | willActiveSelected: PropTypes.object, 31 | /** 参数 date */ 32 | onWillActiveSelected: PropTypes.func, 33 | 34 | /** Date对象,表示可选的最小日期 */ 35 | min: PropTypes.object, 36 | /** Date对象,表示可选的最大日期 */ 37 | max: PropTypes.object, 38 | /** 自定义日期是否可选。传入参数为Date对象,返回true or false。 有此属性则min max无效。 */ 39 | disabledDate: PropTypes.func, 40 | 41 | className: PropTypes.string, 42 | style: PropTypes.object, 43 | 44 | /** 目前全键盘用 */ 45 | onKeyDown: PropTypes.func 46 | } 47 | 48 | Calendar.defaultProps = { 49 | onSelect: _.noop 50 | } 51 | 52 | export default Calendar 53 | -------------------------------------------------------------------------------- /src/component/calendar/index.js: -------------------------------------------------------------------------------- 1 | import Calendar from './calendar' 2 | import RangeCalendar from './range_calendar' 3 | 4 | export { Calendar, RangeCalendar } 5 | -------------------------------------------------------------------------------- /src/component/calendar/week.js: -------------------------------------------------------------------------------- 1 | import { getLocale } from '../../locales' 2 | import React from 'react' 3 | import _ from 'lodash' 4 | import Flex from '../flex' 5 | 6 | const weekDays = [ 7 | getLocale('week__日'), 8 | getLocale('week__一'), 9 | getLocale('week__二'), 10 | getLocale('week__三'), 11 | getLocale('week__四'), 12 | getLocale('week__五'), 13 | getLocale('week__六') 14 | ] 15 | const Week = () => { 16 | return ( 17 | 18 | {_.map(weekDays, (v, i) => ( 19 | 20 | {v} 21 | 22 | ))} 23 | 24 | ) 25 | } 26 | 27 | export default Week 28 | -------------------------------------------------------------------------------- /src/component/carousel/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Carousel from './carousel' 4 | 5 | storiesOf('Carousel', module).add('default', () => ( 6 | 7 |
8 |
9 | 13 |
14 |
15 |
16 | showCarousel1 17 |
18 |
19 | showCarousel2 20 |
21 |
showCarousel3
22 |
23 | showCarousel4 24 |
25 |
26 | )) 27 | -------------------------------------------------------------------------------- /src/component/carousel/style.less: -------------------------------------------------------------------------------- 1 | .gm-carousel-fade { 2 | position: relative; 3 | 4 | &-item { 5 | display: inline-block; 6 | position: absolute; 7 | opacity: 0; 8 | visibility: hidden; 9 | 10 | &-active { 11 | opacity: 1; 12 | visibility: visible; 13 | } 14 | } 15 | 16 | &-footer { 17 | bottom: 5px; 18 | height: 10px; 19 | position: absolute; 20 | list-style-type: none; 21 | padding-inline-start: 0; 22 | 23 | &-li { 24 | float: left; 25 | width: 10px; 26 | height: 10px; 27 | border-radius: 50%; 28 | cursor: pointer; 29 | background-color: #000; 30 | opacity: 0.3; 31 | margin: 5px; 32 | 33 | &-hover { 34 | background-color: #fff; 35 | opacity: 0.6; 36 | border: 0; 37 | } 38 | 39 | &::after { 40 | clear: both; 41 | content: '.'; 42 | display: block; 43 | width: 0; 44 | height: 0; 45 | visibility: hidden; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/component/cascader/stories.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/src/component/cascader/stories.js -------------------------------------------------------------------------------- /src/component/checkbox/index.js: -------------------------------------------------------------------------------- 1 | import Checkbox from './checkbox' 2 | import CheckboxGroup from './checkbox_group' 3 | 4 | export { Checkbox, CheckboxGroup } 5 | -------------------------------------------------------------------------------- /src/component/collapse/collapse.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Collapse from './index' 4 | import { observable } from 'mobx' 5 | 6 | const store = observable({ 7 | isIn: true, 8 | setIsIn() { 9 | this.isIn = !this.isIn 10 | } 11 | }) 12 | 13 | storiesOf('Collapse', module).add('default', () => ( 14 |
15 | 16 | 啦啦啦啦 17 |
18 | )) 19 | -------------------------------------------------------------------------------- /src/component/collapse/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | class Collapse extends React.Component { 6 | render() { 7 | const { children, className, in: isIn, style, ...rest } = this.props 8 | return ( 9 |
22 | {children} 23 |
24 | ) 25 | } 26 | } 27 | 28 | Collapse.propTypes = { 29 | in: PropTypes.bool.isRequired, 30 | 31 | children: PropTypes.any, 32 | className: PropTypes.string, 33 | style: PropTypes.object 34 | } 35 | 36 | export default Collapse 37 | -------------------------------------------------------------------------------- /src/component/color_picker/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { observable } from 'mobx' 4 | import ColorPicker from './' 5 | 6 | const store = observable({ 7 | color: '', 8 | setColor(color) { 9 | this.color = color 10 | } 11 | }) 12 | 13 | storiesOf('ColorPicker', module).add('default', () => ( 14 | store.setColor(value)}> 15 | 16 | 17 | )) 18 | -------------------------------------------------------------------------------- /src/component/color_picker/style.less: -------------------------------------------------------------------------------- 1 | .gm-color-picker { 2 | padding: 10px; 3 | width: 276px; 4 | background: white; 5 | position: relative; 6 | 7 | div { 8 | margin: 3px; 9 | width: 30px; 10 | height: 30px; 11 | border-radius: 4px; 12 | cursor: pointer; 13 | } 14 | 15 | .gm-color-picker-addon { 16 | background: rgb(240, 240, 240); 17 | color: rgb(152, 161, 164); 18 | font-size: 16px; 19 | font-weight: bolder; 20 | line-height: 30px; 21 | text-align: center; 22 | border-top-right-radius: 0; 23 | border-bottom-right-radius: 0; 24 | margin-right: 0; 25 | } 26 | 27 | input { 28 | width: 109px; 29 | font-size: 14px; 30 | color: rgb(102, 102, 102); 31 | border: 0; 32 | outline: none; 33 | height: 30px; 34 | margin: 3px 3px 3px 0; 35 | box-shadow: rgb(240, 240, 240) 0 0 0 1px inset; 36 | border-radius: 0 4px 4px 0; 37 | padding-left: 8px; 38 | } 39 | 40 | .gm-color-picker-value { 41 | position: absolute; 42 | width: 20px; 43 | height: 20px; 44 | bottom: 15px; 45 | right: 20px; 46 | border-radius: 50%; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/component/date_range_picker/style.less: -------------------------------------------------------------------------------- 1 | .gm-date-range-picker-overlay { 2 | .gm-date-range-picker-overlay-calendar { 3 | .gm-calendar-day-will:not(.active) { 4 | // 要屏蔽 will 5 | outline: none; 6 | } 7 | } 8 | } 9 | 10 | .gm-date-range-picker-bottom-text { 11 | color: @brand-primary; 12 | text-align: center; 13 | } 14 | 15 | .gm-date-range-picker-bottom-time { 16 | width: 60px; 17 | height: 24px; 18 | margin-left: 5px; 19 | align-content: center; 20 | border: 1px solid @gm-border-color; 21 | color: @brand-primary; 22 | outline: none; 23 | background-color: #fff; 24 | cursor: pointer; 25 | 26 | &:focus { 27 | border: 1px solid @brand-primary; 28 | } 29 | } 30 | 31 | .gm-date-range-picker-gap { 32 | width: 10px; 33 | height: 32px; 34 | } 35 | 36 | .gm-date-range-picker-left-item { 37 | height: 30px; 38 | line-height: 30px; 39 | text-align: center; 40 | 41 | &:hover { 42 | background-color: #b2d5ff; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/component/date_range_picker/util.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | // 设置moment的时间值 4 | const setTimes = (date, time) => { 5 | // 没有设置时间 6 | if (!time) { 7 | return moment(date) 8 | } 9 | 10 | const _time = moment(time) 11 | 12 | const res = moment(date) 13 | .hour(_time.hour()) 14 | .minute(_time.minute()) 15 | .second(_time.second()) 16 | return res 17 | } 18 | 19 | const getTimeCells = span => { 20 | let time = moment().startOf('day') 21 | const cells = [] 22 | 23 | while (time <= moment().endOf('day')) { 24 | cells.push(time) 25 | time = moment(time + span) 26 | } 27 | return cells 28 | } 29 | 30 | export { setTimes, getTimeCells } 31 | -------------------------------------------------------------------------------- /src/component/divider/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Flex from '../flex' 4 | 5 | class Divider extends React.Component { 6 | render() { 7 | const { children } = this.props 8 | return ( 9 | 10 | 11 |
12 | {typeof children === 'string' ? ( 13 | {children} 14 | ) : ( 15 | children 16 | )} 17 |
18 | 19 | 20 | ) 21 | } 22 | } 23 | 24 | Divider.propTypes = { 25 | children: PropTypes.any 26 | } 27 | 28 | export default Divider 29 | -------------------------------------------------------------------------------- /src/component/divider/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Divider from './index' 4 | 5 | storiesOf('Divider', module).add('default', () => lalala) 6 | -------------------------------------------------------------------------------- /src/component/divider/style.less: -------------------------------------------------------------------------------- 1 | .gm-divider { 2 | .gm-divider-line { 3 | position: relative; 4 | } 5 | 6 | .gm-divider-line::before { 7 | content: " "; 8 | position: absolute; 9 | left: 0; 10 | top: 50%; 11 | width: 100%; 12 | height: 1px; 13 | background: @gm-border-color; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/component/drawer/style.less: -------------------------------------------------------------------------------- 1 | .gm-drawer-mask { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 1020; 8 | background-color: rgba(0, 0, 0, 0.7); 9 | 10 | &.gm-drawer-mask-opacity { 11 | background-color: rgba(0, 0, 0, 0); 12 | } 13 | } 14 | 15 | .gm-drawer { 16 | overflow-x: hidden; 17 | overflow-y: auto; 18 | position: fixed; 19 | top: 0; 20 | right: 0; 21 | bottom: 0; 22 | left: 0; 23 | z-index: 1030; 24 | outline: 0; 25 | 26 | .gm-drawer-content { 27 | background-color: white; 28 | width: auto; 29 | margin: 0 0 0 auto; 30 | height: 100%; 31 | overflow: auto; 32 | } 33 | } 34 | 35 | // 限制移动端最大宽度,防止隐藏close按钮 36 | @media (max-device-width: 766px) and (min-device-width: 0) { 37 | .gm-drawer { 38 | .gm-drawer-content { 39 | max-width: 70vw; 40 | overflow: auto !important; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/component/drop_down/drop_down_item.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | class DropDownItem extends React.Component { 6 | handleClick = () => { 7 | if (this.props.disabled) { 8 | return 9 | } 10 | this.props.onClick() 11 | } 12 | 13 | render() { 14 | const { children, active, className, disabled, ...rest } = this.props 15 | 16 | return ( 17 |
  • 28 | {children} 29 |
  • 30 | ) 31 | } 32 | } 33 | 34 | DropDownItem.propTypes = { 35 | active: PropTypes.bool, 36 | disabled: PropTypes.bool, 37 | onClick: PropTypes.func, 38 | children: PropTypes.any, 39 | className: PropTypes.string, 40 | style: PropTypes.object 41 | } 42 | 43 | export default DropDownItem 44 | -------------------------------------------------------------------------------- /src/component/drop_down/drop_down_items.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | class DropDownItems extends React.Component { 6 | render() { 7 | const { className, children, ...rest } = this.props 8 | return ( 9 |
      10 | {children} 11 |
    12 | ) 13 | } 14 | } 15 | 16 | DropDownItems.propTypes = { 17 | children: PropTypes.any, 18 | className: PropTypes.string, 19 | style: PropTypes.object 20 | } 21 | 22 | export default DropDownItems 23 | -------------------------------------------------------------------------------- /src/component/drop_down/index.js: -------------------------------------------------------------------------------- 1 | import DropDownItems from './drop_down_items' 2 | import DropDownItem from './drop_down_item' 3 | import DropDown from './drop_down' 4 | 5 | export { DropDown, DropDownItem, DropDownItems } 6 | -------------------------------------------------------------------------------- /src/component/drop_down/style.less: -------------------------------------------------------------------------------- 1 | .gm-dropdown-popup { 2 | .dropdown-menu { 3 | display: block; 4 | position: initial; 5 | float: none; 6 | margin-top: 0; 7 | margin-bottom: 0; 8 | } 9 | } 10 | 11 | .gm-dropdown-split-popup { 12 | position: relative; 13 | 14 | .dropdown-menu { 15 | display: block; 16 | position: initial; 17 | float: none; 18 | margin-top: 0; 19 | margin-bottom: 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/component/dropper/style.less: -------------------------------------------------------------------------------- 1 | .gm-dropper { 2 | display: inline-block; 3 | 4 | .gm-dropper-default { 5 | width: 100px; 6 | height: 100px; 7 | border: 2px dashed @gm-border-color; 8 | cursor: pointer; 9 | } 10 | 11 | .gm-dropper-wrap { 12 | display: inline-block; 13 | } 14 | 15 | .gm-dropper-input[type="file"] { 16 | display: none; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/component/editable_text/editable_text.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import EditableText from './' 4 | import Popover from '../popover' 5 | import { observable } from 'mobx' 6 | 7 | const store = observable({ 8 | content: 'hello', 9 | setContent(value) { 10 | this.content = value 11 | } 12 | }) 13 | 14 | storiesOf('EditableText', module).add('default', () => ( 15 |
    16 | store.setContent(value)} 18 | content={store.content} 19 | disabled 20 | /> 21 | store.setContent(value)} 23 | content={store.content} 24 | > 25 | } 29 | type='hover' 30 | popup={ 31 |
    35 | 来源:{store.content} 36 |
    37 | } 38 | > 39 |
    {store.content}
    40 |
    41 |
    42 | store.setContent(value)} 44 | content={store.content} 45 | /> 46 |
    47 | )) 48 | -------------------------------------------------------------------------------- /src/component/editable_text/style.less: -------------------------------------------------------------------------------- 1 | .gm-editable-text { 2 | .gm-editable-text-edit-pen { 3 | color: @brand-primary; 4 | display: none; 5 | } 6 | 7 | &:hover { 8 | .gm-editable-text-edit-pen { 9 | display: inline-block; 10 | } 11 | } 12 | } 13 | 14 | .gm-editable-text-input-wrap { 15 | min-width: 160px; 16 | 17 | .form-control { 18 | min-width: 120px; 19 | display: inline-block; 20 | } 21 | 22 | .gm-editable-text-icon-ok { 23 | color: @brand-primary; 24 | } 25 | 26 | .gm-editable-text-icon-cancel { 27 | color: red; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/component/flex/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Flex from './index' 4 | 5 | storiesOf('Flex', module).add('default', () => , { 6 | info: { 7 | text: ` 8 | 语法见 [Flex](http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html) 9 | 10 | 本组件只是个简单的封装,只提供兼容的属性 11 | ` 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /src/component/flip_number/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import FlipNumber from './index' 4 | import { observable } from 'mobx' 5 | 6 | const store = observable({ 7 | from: 0, 8 | to: 0 9 | }) 10 | 11 | setTimeout(() => { 12 | store.from = 234.2343 13 | store.to = 709394 14 | }) 15 | 16 | storiesOf('FlipNumber', module).add('default', () => ( 17 | 25 | )) 26 | -------------------------------------------------------------------------------- /src/component/flip_number/utils.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import { is } from 'gm-util' 3 | 4 | function formatNum(number, decimals, useGroup) { 5 | return number.toLocaleString(undefined, { 6 | minimumFractionDigits: decimals, 7 | maximumFractionDigits: decimals, 8 | useGrouping: useGroup 9 | }) 10 | } 11 | 12 | function getNumLength(str1, str2) { 13 | return Math.max(str1.length, str2.length) 14 | } 15 | 16 | function filterForNum(strArr) { 17 | return _.filter(strArr, item => is.number(item)) 18 | } 19 | 20 | /** 21 | * @description 根据字符串返回相应的反转字符数组以及符号数组 22 | * @augments numStr 需要转换成数组的数字字符串 23 | * @augments length 需要转换成的长度 24 | */ 25 | function getRawArray(numStr, length) { 26 | const alignNum = (str, len) => { 27 | return str.length < len ? alignNum(`0${str}`, len) : str 28 | } 29 | const symbolList = [] 30 | const rawStrArr = alignNum(numStr, length).split('') 31 | _.forEach(rawStrArr, (item, index) => { 32 | if (item === ',' || item === '.') { 33 | symbolList.push({ 34 | symbol: item, 35 | position: index 36 | }) 37 | } 38 | }) 39 | const rawList = filterForNum(rawStrArr).reverse() 40 | _.forEach(symbolList, item => { 41 | rawList.splice(item.position, 0, item.symbol) 42 | }) 43 | return { rawList, symbolList } 44 | } 45 | 46 | export { formatNum, filterForNum, getNumLength, getRawArray } 47 | -------------------------------------------------------------------------------- /src/component/form/form_block.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Flex from '../flex' 4 | import _ from 'lodash' 5 | import classNames from 'classnames' 6 | import { withWrapContext, colWidthDefault } from './util' 7 | 8 | /** 一堆同类表单元素的集 */ 9 | const FormBlock = withWrapContext( 10 | ({ children, disabledCol, inline, className, col, style, colWidth }) => { 11 | const _cw = colWidth ? +colWidth.replace('px', '') : colWidthDefault 12 | const _style = Object.assign( 13 | {}, 14 | style, 15 | disabledCol || inline 16 | ? {} 17 | : { 18 | width: _cw * col 19 | } 20 | ) 21 | 22 | return ( 23 | 28 | {_.map(React.Children.toArray(children), (child, i) => { 29 | return ( 30 | 31 | {child} 32 | 33 | ) 34 | })} 35 | 36 | ) 37 | } 38 | ) 39 | 40 | FormBlock.displayName = 'FormBlock' 41 | 42 | FormBlock.propTypes = { 43 | /** 占用栏数 */ 44 | col: PropTypes.oneOf([1, 2, 3]), 45 | 46 | /** Form 传下来,不要动 */ 47 | disabledCol: PropTypes.bool, 48 | /** Form 传下来,不要动 */ 49 | inline: PropTypes.bool, 50 | 51 | className: PropTypes.string, 52 | style: PropTypes.object 53 | } 54 | 55 | FormBlock.defaultProps = { 56 | col: 1 57 | } 58 | 59 | export default FormBlock 60 | -------------------------------------------------------------------------------- /src/component/form/form_button.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withWrapContext } from './util' 4 | 5 | const FormButton = withWrapContext( 6 | ({ labelWidth, btnPosition, inline, children }) => { 7 | const style = { 8 | marginLeft: 9 | btnPosition === 'left' && !inline && labelWidth ? labelWidth : 0 10 | } 11 | 12 | const position = btnPosition ? `text-${btnPosition}` : 'text-center' 13 | 14 | return ( 15 |
    16 | {children} 17 |
    18 | ) 19 | } 20 | ) 21 | 22 | FormButton.propTypes = { 23 | /** 由 Form 传下来 */ 24 | labelWidth: PropTypes.string, 25 | /** 由 Form 传下来, 也可自定义 */ 26 | btnPosition: PropTypes.oneOf(['center', 'left', 'right']) 27 | } 28 | 29 | export default FormButton 30 | -------------------------------------------------------------------------------- /src/component/form/index.js: -------------------------------------------------------------------------------- 1 | import Form from './form' 2 | import FormItem from './form_item' 3 | import FormButton from './form_button' 4 | import FormBlock from './form_block' 5 | import FormGroup from './form_group' 6 | import FormPanel from './form_panel' 7 | 8 | export { Form, FormItem, FormButton, FormBlock, FormGroup, FormPanel } 9 | -------------------------------------------------------------------------------- /src/component/form/util.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | const WrapContext = React.createContext(null) 3 | // 暂定 4 | const colWidthDefault = 320 5 | 6 | const withWrapContext = Component => { 7 | return props => { 8 | const consumer = useContext(WrapContext) 9 | return 10 | } 11 | } 12 | 13 | export { WrapContext, withWrapContext, colWidthDefault } 14 | -------------------------------------------------------------------------------- /src/component/function_set/overlay.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import PropTypes from 'prop-types' 3 | import LevelList from '../level_list' 4 | import _ from 'lodash' 5 | 6 | function processDataWithValue(data, map, pre = '') { 7 | return _.map(data, (v, i) => { 8 | const value = `${pre}_${i}` 9 | map[value] = v 10 | 11 | if (v.children) { 12 | v.children = processDataWithValue(v.children, map, value) 13 | } 14 | 15 | return { 16 | value, 17 | ...v 18 | } 19 | }) 20 | } 21 | 22 | const FunctionSetOverlay = props => { 23 | const { data, onSelect, isReverse } = props 24 | const [will, setWill] = useState([]) 25 | 26 | // 做个map存起来,方便快速通过 value 找到 item 27 | const map = {} 28 | const newData = processDataWithValue(data, map) 29 | 30 | const handleSelect = selected => { 31 | // 取最后一个 32 | const item = map[selected.slice(-1)[0]] 33 | onSelect(item) 34 | } 35 | 36 | return ( 37 | setWill(will)} 43 | isReverse={isReverse} 44 | isForFunctionSet 45 | /> 46 | ) 47 | } 48 | 49 | FunctionSetOverlay.propTypes = { 50 | /** [{text, disabled, onClick, children}] */ 51 | data: PropTypes.array.isRequired, 52 | onSelect: PropTypes.func.isRequired, 53 | isReverse: PropTypes.bool 54 | } 55 | 56 | export default FunctionSetOverlay 57 | -------------------------------------------------------------------------------- /src/component/grid/index.js: -------------------------------------------------------------------------------- 1 | import Col from './col' 2 | import Row from './row' 3 | 4 | export { Col, Row } 5 | -------------------------------------------------------------------------------- /src/component/grid/mixin.less: -------------------------------------------------------------------------------- 1 | .gm-grid-float-columns(@class) { 2 | .col(@index) { 3 | // initial 4 | @item: ~'.gm-grid-col@{class}-@{index}'; 5 | .col((@index + 1), @item); 6 | } 7 | .col(@index, @list) when (@index =< @gm-grid-columns) { 8 | // general 9 | @item: ~'.gm-grid-col@{class}-@{index}'; 10 | .col((@index + 1), ~'@{list}, @{item}'); 11 | } 12 | .col(@index, @list) when (@index > @gm-grid-columns) { 13 | // terminal 14 | @{list} { 15 | flex: 0 0 auto; 16 | float: left; 17 | } 18 | } 19 | .col(1); // kickstart it 20 | } 21 | 22 | .gm-grid-loop-columns(@index, @class) when (@index > 0) { 23 | .gm-grid-col@{class}-@{index} { 24 | display: block; 25 | box-sizing: border-box; 26 | width: percentage((@index / @gm-grid-columns)); 27 | } 28 | 29 | .gm-grid-col@{class}-offset-@{index} { 30 | margin-left: percentage((@index / @gm-grid-columns)); 31 | } 32 | .gm-grid-loop-columns((@index - 1), @class); 33 | } 34 | 35 | .gm-grid-loop-columns(@index, @class) when (@index = 0) { 36 | .gm-grid-col@{class}-@{index} { 37 | display: none; 38 | } 39 | 40 | .gm-grid-col@{class}-offset-@{index} { 41 | margin-left: 0; 42 | } 43 | } 44 | 45 | .gm-grid(@class: ~'') { 46 | .gm-grid-float-columns(@class); 47 | .gm-grid-loop-columns(@gm-grid-columns, @class); 48 | } 49 | -------------------------------------------------------------------------------- /src/component/grid/row.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Flex from '../flex' 3 | import classNames from 'classnames' 4 | import PropTypes from 'prop-types' 5 | import { WrapContext } from './util' 6 | 7 | /** 8 | * Flex 布局 9 | * 10 | * Flex 的props都可用 11 | * */ 12 | const Row = props => { 13 | const { className, gutter, style, children, ...rest } = props 14 | const rowStyle = 15 | gutter > 0 16 | ? { marginLeft: gutter / -2, marginRight: gutter / -2, ...style } 17 | : style 18 | return ( 19 | 20 | 27 | {children} 28 | 29 | 30 | ) 31 | } 32 | 33 | Row.propTypes = { 34 | style: PropTypes.object, 35 | className: PropTypes.string, 36 | /** 栅格间隔,可以写成像素值或支持响应式的对象写法 { xs: 8, sm: 16, md: 24}, 默认为10 */ 37 | gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number]) 38 | } 39 | 40 | Row.defaultProps = { 41 | gutter: 0 42 | } 43 | 44 | export default Row 45 | -------------------------------------------------------------------------------- /src/component/grid/style.less: -------------------------------------------------------------------------------- 1 | @import './mixin'; 2 | 3 | .gm-grid-row { 4 | position: relative; 5 | height: auto; 6 | .clearfix(); 7 | } 8 | 9 | .gm-grid(); // 不设置size时 10 | .gm-grid(-sm); // 默认的 11 | 12 | @media (min-width: @gm-screen-sm-min) { 13 | .gm-grid(-sm); 14 | } 15 | 16 | @media (min-width: @gm-screen-md-min) { 17 | .gm-grid(-md); 18 | } 19 | 20 | @media (min-width: @gm-screen-lg-min) { 21 | .gm-grid(-lg); 22 | } 23 | 24 | @media (min-width: @gm-screen-xl-min) { 25 | .gm-grid(-xl); 26 | } 27 | -------------------------------------------------------------------------------- /src/component/grid/util.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | const WrapContext = React.createContext(null) 3 | 4 | const withWrapContext = Component => { 5 | return props => { 6 | const consumer = useContext(WrapContext) 7 | return 8 | } 9 | } 10 | 11 | export { WrapContext, withWrapContext } 12 | -------------------------------------------------------------------------------- /src/component/icon_down_up/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import SVGDown from '../../../svg/down.svg' 4 | import classNames from 'classnames' 5 | 6 | const IconDownUp = props => { 7 | const { active, className, ...rest } = props 8 | return ( 9 | 19 | ) 20 | } 21 | 22 | IconDownUp.propTypes = { 23 | active: PropTypes.bool, 24 | className: PropTypes.string, 25 | style: PropTypes.object 26 | } 27 | 28 | export default IconDownUp 29 | -------------------------------------------------------------------------------- /src/component/icon_down_up/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import IconDownUp from './' 4 | import { observable } from 'mobx' 5 | 6 | const store = observable({ 7 | active: false, 8 | toggle() { 9 | this.active = !this.active 10 | } 11 | }) 12 | 13 | storiesOf('IconDownUp', module).add('default', () => ( 14 |
    15 | 16 | 17 |
    18 | )) 19 | -------------------------------------------------------------------------------- /src/component/icon_down_up/style.less: -------------------------------------------------------------------------------- 1 | .gm-icon-down-up { 2 | transform: rotate(0deg); 3 | transition: 0.5s ease all; 4 | 5 | &.active { 6 | transform: rotate(180deg); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/component/image_preview/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PreviewModal from './preview_modal' 3 | import CleanModal from '../modal/clean_modal' 4 | 5 | const ImagePreview = props => { 6 | CleanModal.render({ 7 | children: , 8 | show: true, 9 | onHide: CleanModal.hide, 10 | disableMaskClose: true, 11 | style: { 12 | background: 'rgba(0, 0, 0, 1)', 13 | margin: '0', 14 | width: '100%', 15 | height: '100%' 16 | } 17 | }) 18 | } 19 | 20 | export default ImagePreview 21 | -------------------------------------------------------------------------------- /src/component/img_uploader/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import ImgUploader from './index' 4 | import { observable } from 'mobx' 5 | 6 | const store = observable({ 7 | data: [ 8 | 'https://js.guanmai.cn/static_storage/json/common/logo/default/logo.pure.png' 9 | ], 10 | setData(newData) { 11 | this.data = newData 12 | } 13 | }) 14 | 15 | const handleUpload = files => { 16 | console.log(files) 17 | // 调用方做突破尺寸和文件大小判断 18 | 19 | return Promise.resolve([ 20 | 'https://js.guanmai.cn/static_storage/json/common/logo/default/logo.pure.png' 21 | ]) 22 | } 23 | 24 | storiesOf('ImgUploader', module) 25 | .add('default', () => ( 26 |
    27 |
    28 | store.setData(data)} 32 | accept='image/*' 33 | desc='图片尺寸720*720像素,大小小于1M' 34 | multiple 35 | /> 36 |
    37 | )) 38 | .add('disabled', () => ( 39 |
    40 |
    41 | store.setData(data)} 46 | accept='image/*' 47 | desc='图片尺寸720*720像素,大小小于1M' 48 | multiple 49 | /> 50 |
    51 | )) 52 | -------------------------------------------------------------------------------- /src/component/img_uploader/style.less: -------------------------------------------------------------------------------- 1 | .gm-img-uploader { 2 | display: inline-block; 3 | 4 | .gm-img-uploader-item { 5 | position: relative; 6 | margin-right: 10px; 7 | 8 | .gm-img-uploader-close { 9 | position: absolute; 10 | cursor: pointer; 11 | display: none; 12 | right: -0.5em; 13 | top: -0.5em; 14 | } 15 | 16 | &:hover { 17 | .gm-img-uploader-close { 18 | display: block; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/component/input/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | /** 没什么,就一个input,多了个类名 gm-input 用来和库配合做UI */ 6 | const Input = forwardRef((props, ref) => { 7 | const { className, ...rest } = props 8 | return ( 9 | 10 | ) 11 | }) 12 | 13 | Input.propTypes = { 14 | className: PropTypes.string 15 | } 16 | 17 | export default Input 18 | -------------------------------------------------------------------------------- /src/component/input_number/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import InputNumberV2 from './number' 4 | import { observable } from 'mobx' 5 | 6 | const store = observable({ 7 | value: null, 8 | setValue(value) { 9 | this.value = value 10 | } 11 | }) 12 | 13 | storiesOf('InputNumberV2', module).add('default', () => ( 14 | { 17 | console.log('onChange', value) 18 | store.setValue(value) 19 | }} 20 | /> 21 | )) 22 | -------------------------------------------------------------------------------- /src/component/input_number/style.less: -------------------------------------------------------------------------------- 1 | .gm-input-number { 2 | /* Firefox */ 3 | -moz-appearance: textfield; 4 | } 5 | 6 | .gm-input-number::-webkit-outer-spin-button, 7 | .gm-input-number::-webkit-inner-spin-button { 8 | margin: 0; 9 | -webkit-appearance: none !important; 10 | } 11 | -------------------------------------------------------------------------------- /src/component/level_list/style.less: -------------------------------------------------------------------------------- 1 | .gm-level-list { 2 | height: 220px; 3 | 4 | .gm-level-list-item { 5 | min-width: 120px; 6 | max-width: 180px; 7 | border: 1px solid @gm-border-color; 8 | margin-left: -1px; 9 | background: white; 10 | 11 | &:first-child { 12 | margin-left: 0; 13 | } 14 | 15 | .gm-level-list-item-title { 16 | color: @gm-color-second; 17 | padding: 5px; 18 | } 19 | 20 | .gm-list { 21 | border: none; 22 | height: 218px; 23 | } 24 | 25 | .gm-level-list-item-right { 26 | position: absolute; 27 | right: -6px; 28 | top: 2px; 29 | } 30 | } 31 | 32 | &.gm-level-list-for-function-set { 33 | height: auto; 34 | background-color: transparent; 35 | 36 | .gm-level-list-item { 37 | border: none; 38 | max-width: none; 39 | background: transparent; 40 | 41 | .gm-list { 42 | border: 1px solid @gm-border-color; 43 | height: auto; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/component/level_list/util.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | // 把树的数据达成多个数组,方便展示数据浮层 4 | const getLevel = (data, selected) => { 5 | const result = [data] 6 | 7 | _.each(selected, (item, i) => { 8 | const match = _.find(result[i], v => v.value === item) 9 | 10 | if (match) { 11 | if (match.children) { 12 | result.push(match.children) 13 | } 14 | } 15 | }) 16 | 17 | return result 18 | } 19 | 20 | const isLeaf = (data, willActiveSelected) => {} 21 | 22 | export { getLevel, isLeaf } 23 | -------------------------------------------------------------------------------- /src/component/list/style.less: -------------------------------------------------------------------------------- 1 | // 注意注意 2 | // gm-list gm-list-item.active 被 Select 使用 3 | .gm-list { 4 | border: 1px solid @gm-border-color; 5 | background: white; 6 | // 注意,overflow-y 会被 FunctionSet 覆盖 7 | overflow-y: auto; 8 | min-width: 80px; 9 | 10 | .gm-list-item { 11 | cursor: pointer; 12 | padding: 5px 10px; 13 | background: #fff; 14 | 15 | &.active { 16 | color: @brand-primary; 17 | } 18 | 19 | &.disabled { 20 | cursor: not-allowed; 21 | color: @gm-color-fourth; 22 | } 23 | 24 | &.will-active { 25 | background-color: @gm-list-bg-hover; 26 | } 27 | 28 | &:hover { 29 | background-color: @gm-list-bg-hover; 30 | 31 | &.disabled { 32 | color: @gm-color-third; 33 | } 34 | } 35 | } 36 | 37 | &.gm-list-group { 38 | .gm-list-group-item { 39 | border-bottom: 1px solid @gm-border-color; 40 | 41 | &:last-child { 42 | border-bottom: none; 43 | } 44 | } 45 | 46 | .gm-list-label { 47 | color: @gm-color-second; 48 | padding: 5px 10px; 49 | } 50 | 51 | .gm-list-item { 52 | padding: 5px 10px 5px 22px; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/component/loading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | class Loading extends React.Component { 6 | render() { 7 | const { style, size, text, className, ...rest } = this.props 8 | 9 | return ( 10 |
    11 | 20 | 27 | 28 | {text &&

    {text}

    } 29 |
    30 | ) 31 | } 32 | } 33 | 34 | Loading.propTypes = { 35 | text: PropTypes.string, 36 | size: PropTypes.number, 37 | className: PropTypes.string, 38 | style: PropTypes.object 39 | } 40 | 41 | Loading.defaultProps = { 42 | size: 40 43 | } 44 | 45 | export default Loading 46 | -------------------------------------------------------------------------------- /src/component/loading/loading_chunk.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | import Loading from './index' 5 | 6 | class LoadingChunk extends React.Component { 7 | render() { 8 | const { 9 | loading, 10 | style, 11 | size, 12 | text, 13 | className, 14 | children, 15 | ...rest 16 | } = this.props 17 | 18 | return ( 19 |
    25 | {children ||
    } 26 | {loading && ( 27 |
    28 | 38 |
    39 | )} 40 |
    41 | ) 42 | } 43 | } 44 | 45 | LoadingChunk.propTypes = { 46 | loading: PropTypes.bool, 47 | text: PropTypes.string, 48 | size: PropTypes.number, 49 | children: PropTypes.any, 50 | className: PropTypes.string, 51 | style: PropTypes.object 52 | } 53 | 54 | LoadingChunk.defaultProps = { 55 | size: 50, 56 | loading: false 57 | } 58 | 59 | export default LoadingChunk 60 | -------------------------------------------------------------------------------- /src/component/loading/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Loading from './index' 4 | import LoadingChunk from './loading_chunk' 5 | import LoadingFullScreen from './loading_full_screen' 6 | storiesOf('Loading', module) 7 | .add('default', () => ) 8 | .add('size', () => ) 9 | .add('LoadingChunk', () => ( 10 | 11 |
    16 | asdfasfafa 17 |
    18 |
    19 | )) 20 | .add('LoadingChunk with text', () => ( 21 | 22 |
    27 | asdfasfafa 28 |
    29 |
    30 | )) 31 | .add('LoadingFullScreen', () => ( 32 | 45 | )) 46 | -------------------------------------------------------------------------------- /src/component/mask/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames' 4 | 5 | class Mask extends React.Component { 6 | render() { 7 | const { className, style, opacity, ...rest } = this.props 8 | 9 | return ( 10 |
    20 | ) 21 | } 22 | } 23 | 24 | Mask.propTypes = { 25 | opacity: PropTypes.number, 26 | className: PropTypes.string, 27 | style: PropTypes.object 28 | } 29 | 30 | Mask.defaultProps = { 31 | opacity: 0.5 32 | } 33 | 34 | export default Mask 35 | -------------------------------------------------------------------------------- /src/component/mask/style.less: -------------------------------------------------------------------------------- 1 | .gm-mask { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | bottom: 0; 6 | right: 0; 7 | width: 100%; 8 | height: 100%; 9 | z-index: 1000; 10 | } 11 | -------------------------------------------------------------------------------- /src/component/modal/clean_modal.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import Modal from './index' 3 | import _ from 'lodash' 4 | 5 | const CleanModal = {} 6 | 7 | CleanModal.render = props => { 8 | const cleanProps = { 9 | ...props, 10 | className: 'gm-modal-clean' 11 | } 12 | Modal.render(cleanProps) 13 | } 14 | 15 | CleanModal.hide = () => { 16 | Modal.hide() 17 | } 18 | 19 | CleanModal.propTypes = { 20 | show: PropTypes.bool.isRequired, 21 | onHide: PropTypes.func, 22 | disableMaskClose: PropTypes.bool, 23 | size: PropTypes.string, // lg md sm 24 | title: PropTypes.string, 25 | okBtnClassName: PropTypes.string, // Modal confirm okbtn的className 26 | noContentPadding: PropTypes.bool 27 | } 28 | 29 | CleanModal.defaultProps = { 30 | onHide: _.noop, 31 | size: 'md', 32 | disableMaskClose: false, 33 | noContentPadding: false 34 | } 35 | 36 | export default CleanModal 37 | -------------------------------------------------------------------------------- /src/component/modal/right_side_modal.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import Modal from './index' 3 | import _ from 'lodash' 4 | 5 | const RightSideModal = {} 6 | 7 | RightSideModal.render = props => { 8 | const rightSideProps = { 9 | ...props, 10 | animName: 'fade-in-left', 11 | className: 'gm-modal-right-side' 12 | } 13 | Modal.render(rightSideProps) 14 | } 15 | 16 | RightSideModal.hide = () => { 17 | Modal.hide() 18 | } 19 | 20 | RightSideModal.propTypes = { 21 | show: PropTypes.bool.isRequired, 22 | onHide: PropTypes.func, 23 | disableMaskClose: PropTypes.bool, 24 | size: PropTypes.string, // lg md sm 25 | title: PropTypes.string, 26 | okBtnClassName: PropTypes.string, // Modal confirm okbtn的className 27 | noContentPadding: PropTypes.bool 28 | } 29 | 30 | RightSideModal.defaultProps = { 31 | onHide: _.noop, 32 | size: 'md', 33 | disableMaskClose: false, 34 | noContentPadding: false 35 | } 36 | 37 | export default RightSideModal 38 | -------------------------------------------------------------------------------- /src/component/nprogress/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import LayoutRoot from '../layout_root' 3 | 4 | const NProgress = () =>
    5 | 6 | let timer = null 7 | let reqLength = 0 8 | 9 | const NProgressStatics = { 10 | start: function() { 11 | reqLength = reqLength + 1 12 | if (reqLength === 1) { 13 | if (timer) { 14 | clearTimeout(timer) 15 | timer = null 16 | } 17 | LayoutRoot.setComponent(LayoutRoot.TYPE.NPROGRESS, ) 18 | } 19 | }, 20 | done: function() { 21 | reqLength = reqLength - 1 22 | const nProgress = document.querySelector('.gm-nprogress') 23 | if (!reqLength && !timer) { 24 | nProgress && (nProgress.className = 'gm-nprogress gm-nprogress-completed') 25 | timer = setTimeout(function() { 26 | LayoutRoot.removeComponent(LayoutRoot.TYPE.NPROGRESS) 27 | timer = null 28 | }, 250) 29 | } 30 | } 31 | } 32 | 33 | Object.assign(NProgress, NProgressStatics) 34 | export default NProgress 35 | -------------------------------------------------------------------------------- /src/component/nprogress/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import NProgress from './index' 4 | 5 | storiesOf('NProgress', module).add('default', () => ( 6 |
    7 | 14 | 21 |
    22 | )) 23 | -------------------------------------------------------------------------------- /src/component/nprogress/style.less: -------------------------------------------------------------------------------- 1 | .gm-nprogress { 2 | transition: all 200ms ease; 3 | height: 2px; 4 | background: @brand-primary; 5 | width: 100%; 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | right: 0; 10 | z-index: 9999; 11 | } 12 | 13 | .gm-nprogress-loading { 14 | animation: gm-nprogress-loading 1s linear; 15 | animation-fill-mode: forwards; 16 | } 17 | 18 | .gm-nprogress-completed { 19 | transform: translateX(0); 20 | visibility: hidden; 21 | } 22 | 23 | @keyframes gm-nprogress-loading { 24 | 0% { 25 | transform: translateX(-100%); 26 | } 27 | 28 | 20% { 29 | transform: translateX(-50%); 30 | } 31 | 32 | 50% { 33 | transform: translateX(-20%); 34 | } 35 | 36 | 100% { 37 | transform: translateX(-10%); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/component/pagination/left.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Select } from '../select' 4 | import Flex from '../flex' 5 | 6 | const limitData = [ 7 | { value: 10, text: 10 }, 8 | { value: 20, text: 20 }, 9 | { value: 50, text: 50 } 10 | ] 11 | 12 | const Limit = ({ value, onChange }) => { 13 | return ( 14 | store.setData(event.target.value)} 22 | /> 23 | 24 |
    25 | ), 26 | { 27 | info: { 28 | text: ` 29 | ### Static 30 | - \`set(key, value)\` 31 | - \`get(key)\` 32 | - \`remove(key)\` 33 | - \`clear\` 慎用,清除本域名全部存储 34 | - \`getAll\` 拿到全部存储,以Obj形式返回 35 | ` 36 | } 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /src/component/switch/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Switch from './index' 4 | 5 | storiesOf('Switch', module) 6 | .add('default', () => ) 7 | .add('有文字', () => ) 8 | -------------------------------------------------------------------------------- /src/component/switch/style.less: -------------------------------------------------------------------------------- 1 | .gm-switch { 2 | position: relative; 3 | -webkit-appearance: none; 4 | height: 22px; 5 | border-radius: 11px; 6 | background-color: #afb5c0; 7 | 8 | &::before { 9 | position: absolute; 10 | content: ''; 11 | top: 1px; 12 | left: 1px; 13 | width: 20px; 14 | height: 20px; 15 | border-radius: 50%; 16 | background-color: #fff; 17 | transition: all 0.35s; 18 | } 19 | 20 | &::after { 21 | content: attr(data-text); 22 | color: white; 23 | padding-left: 24px; 24 | line-height: 22px; 25 | transition: all 0.35s; 26 | } 27 | } 28 | 29 | input.gm-switch { 30 | margin: 0; 31 | } 32 | 33 | .gm-switch:checked { 34 | background-color: @brand-primary; 35 | 36 | &::before { 37 | left: 100%; 38 | transform: translateX(-100%); 39 | margin-left: -1px; 40 | } 41 | 42 | &::after { 43 | padding-left: 6px; 44 | } 45 | 46 | &.gm-switch-disabled { 47 | cursor: @cursor-disabled; 48 | .opacity(0.6); 49 | } 50 | 51 | &.gm-switch-primary { 52 | background-color: @brand-primary; 53 | } 54 | 55 | &.gm-switch-success { 56 | background-color: @brand-success; 57 | } 58 | 59 | &.gm-switch-info { 60 | background-color: @brand-info; 61 | } 62 | 63 | &.gm-switch-warning { 64 | background-color: @brand-warning; 65 | } 66 | 67 | &.gm-switch-danger { 68 | background-color: @brand-danger; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/component/table_select/style.less: -------------------------------------------------------------------------------- 1 | .gm-table-select-popup { 2 | .gm-list.gm-list-group { 3 | .gm-list-label { 4 | background: @gm-table-bg-accent; 5 | color: @gm-color-first; 6 | } 7 | 8 | .gm-list-item { 9 | padding: 8px 10px 5px 10px; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/component/table_select/util.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | function getColumnKey(column) { 4 | // 如果是字符串就取 accessor 5 | if (_.isString(column.accessor)) { 6 | return column.accessor 7 | } 8 | // 如果 accessor 是函数,则一定会提供 id,否则 react-table 会报错 9 | else if (_.isFunction(column.accessor) && column.id) { 10 | return column.id 11 | } 12 | // 额外的情况,有些时候只有id,比如 diy 存储就只存了 id,因为 函数没法存储 13 | else if (column.id) { 14 | return column.id 15 | } 16 | 17 | // 其他情况没法获得 key 18 | return null 19 | } 20 | 21 | export { getColumnKey } 22 | -------------------------------------------------------------------------------- /src/component/tabs/style.less: -------------------------------------------------------------------------------- 1 | .gm-tabs-container { 2 | overflow-x: auto; 3 | 4 | .gm-tabs { 5 | white-space: nowrap; 6 | border-bottom: 1px solid fadeout(@gm-frame-border-color, 50%); 7 | height: 40px; 8 | 9 | .gm-tab { 10 | display: inline-block; 11 | border-radius: 4px 4px 0 0; 12 | height: 40px; 13 | font-size: 14px; 14 | color: @gm-color-fourth; 15 | border: 1px solid fadeout(@gm-frame-border-color, 50%); 16 | margin-right: 1px; 17 | background-color: #e8eaf0; 18 | cursor: pointer; 19 | padding: 8px 12px; 20 | transition: background-color 0.4s; 21 | 22 | &:hover { 23 | color: @gm-color-first; 24 | } 25 | 26 | &.active { 27 | color: @gm-color-first; 28 | background-color: #fff; 29 | border-bottom: 1px solid transparent; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/component/tabs/tabs.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Tabs from './tabs' 4 | import { observable } from 'mobx' 5 | import Button from '../button' 6 | 7 | const store = observable({ 8 | active: 0, 9 | changeActive(index) { 10 | this.active = index 11 | } 12 | }) 13 | const tabs = ['第一个', '第二个', '第三个'] 14 | storiesOf('Tabs', module) 15 | .add('Control', () => ( 16 | store.changeActive(index)} 20 | > 21 | 22 | 23 | 24 | 25 | )) 26 | .add('UnControl', () => ( 27 | 28 | 29 | 30 | 31 | 32 | )) 33 | .add('Lazy', () => ( 34 | 35 | 36 | 37 | 38 | 39 | )) 40 | 41 | const Buttons = () => { 42 | const [state, changeState] = React.useState(0) 43 | 44 | const handleClick = () => { 45 | changeState(state + 1) 46 | } 47 | return 48 | } 49 | -------------------------------------------------------------------------------- /src/component/time_span/style.less: -------------------------------------------------------------------------------- 1 | .gm-time-span { 2 | width: 390px; 3 | overflow: hidden; 4 | border: 1px solid @gm-border-color; 5 | background: white; 6 | padding: 10px 0; 7 | 8 | .gm-time-span-list { 9 | width: 130px; 10 | padding: 0 5px; 11 | 12 | .gm-time-span-list-cell { 13 | color: black; 14 | text-align: center; 15 | cursor: pointer; 16 | height: 22px; 17 | margin: 2px 5px; 18 | line-height: 22px; 19 | border: 1px solid transparent; 20 | 21 | &:hover { 22 | background-color: @brand-primary; 23 | color: white; 24 | } 25 | 26 | &.active { 27 | border: 1px solid @brand-primary; 28 | } 29 | 30 | &.disabled { 31 | background: white; 32 | color: @gm-color-second; 33 | cursor: not-allowed; 34 | } 35 | } 36 | } 37 | } 38 | 39 | .gm-time-span-picker { 40 | vertical-align: middle; 41 | display: inline-block; 42 | 43 | .gm-time-span { 44 | border: none; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/component/tip/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Tip from './index' 4 | 5 | storiesOf('Tip', module).add( 6 | 'default', 7 | () => ( 8 |
    9 |
    10 | 啊啊啊 11 | 啊啊啊 12 | 啊啊啊 13 | 啊啊啊 14 | 15 | 啊啊啊 16 | 17 |
    18 | 24 | 36 | 42 |
    43 | ), 44 | { 45 | info: { 46 | text: ` 47 | ### Static 48 | 49 | 方法返回 id ,可以通过 clear(id) 来关闭指定的 tip 50 | 51 | - \`success()\` 52 | - \`info()\` 53 | - \`warning()\` 54 | - \`danger()\` 55 | - \`clear(id)\` 56 | - \`clearAll()\` 57 | ` 58 | } 59 | } 60 | ) 61 | -------------------------------------------------------------------------------- /src/component/tip/style.less: -------------------------------------------------------------------------------- 1 | .gm-tip { 2 | position: relative; 3 | display: inline-block; 4 | min-width: 250px; 5 | cursor: pointer; 6 | } 7 | 8 | .gm-tip .panel-body { 9 | padding-left: 40px; 10 | } 11 | 12 | .gm-tip .close { 13 | margin-right: 5px; 14 | } 15 | 16 | .gm-tip i { 17 | top: 50%; 18 | position: absolute; 19 | margin-top: -0.5em; 20 | margin-left: 10px; 21 | font-size: 2em; 22 | } 23 | 24 | .gm-tips { 25 | position: fixed; 26 | right: 10px; 27 | top: 10px; 28 | z-index: 7000; 29 | max-width: 450px; 30 | } 31 | 32 | .gm-tips-cell { 33 | float: right; 34 | clear: both; 35 | } 36 | 37 | @media print { 38 | .gm-tip { 39 | display: none; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/component/tool_tip/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Popover from '../popover' 4 | import classNames from 'classnames' 5 | import SVGQuestionCircle from '../../../svg/question-circle-o.svg' 6 | 7 | const ToolTip = props => { 8 | const { 9 | popup, 10 | children, 11 | right, 12 | top, 13 | center, 14 | showArrow, 15 | className, 16 | ...rest 17 | } = props 18 | 19 | return ( 20 | 30 | {children !== undefined ? ( 31 | children 32 | ) : ( 33 | 34 | 35 | 36 | )} 37 | 38 | ) 39 | } 40 | 41 | ToolTip.propTypes = { 42 | children: PropTypes.element, 43 | popup: PropTypes.element, 44 | 45 | right: PropTypes.bool, 46 | top: PropTypes.bool, 47 | center: PropTypes.bool, 48 | 49 | showArrow: PropTypes.bool, 50 | className: PropTypes.string, 51 | style: PropTypes.object 52 | } 53 | 54 | ToolTip.defaultProps = { 55 | showArrow: true 56 | } 57 | 58 | export default ToolTip 59 | -------------------------------------------------------------------------------- /src/component/tool_tip/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import ToolTip from './index' 4 | 5 | storiesOf('ToolTip', module).add('default', () => ( 6 |
    7 | hello
    } 9 | /> 10 | hello
    } 12 | > 13 | hover tip 14 | 15 |
    16 | hello
    } 19 | > 20 | right hover tip 21 | 22 | hello
    } 25 | > 26 | center hover tip 27 | 28 |
    29 | hello
    } 32 | > 33 | top hover tip 34 | 35 |
    36 | )) 37 | -------------------------------------------------------------------------------- /src/component/transfer/index.js: -------------------------------------------------------------------------------- 1 | import Transfer from './transfer' 2 | import TransferGroup from './transfer_group' 3 | 4 | export { Transfer, TransferGroup } 5 | -------------------------------------------------------------------------------- /src/component/transfer/style.less: -------------------------------------------------------------------------------- 1 | .gm-transfer { 2 | .gm-transfer-box { 3 | .gm-transfer-box-filter { 4 | position: relative; 5 | 6 | i { 7 | position: absolute; 8 | left: 7px; 9 | top: 10px; 10 | z-index: 2; 11 | } 12 | 13 | input { 14 | padding-left: 26px; 15 | border-top: none; 16 | border-right: none; 17 | border-left: none; 18 | box-shadow: none; 19 | } 20 | } 21 | 22 | .gm-transfer-box-list { 23 | .gm-checkbox-group { 24 | label { 25 | padding: 3px 6px; 26 | 27 | &:hover { 28 | background: #f5f5f5; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/component/tree/bottom.js: -------------------------------------------------------------------------------- 1 | import { getLocale } from '../../locales' 2 | import React from 'react' 3 | import PropTypes from 'prop-types' 4 | import Flex from '../flex' 5 | import { Checkbox } from '../checkbox' 6 | 7 | const Bottom = props => { 8 | const { 9 | checkedAll, 10 | onChange, 11 | selectValuesLength, 12 | leafListLength, 13 | disabled 14 | } = props 15 | 16 | return ( 17 | 18 | 24 | {getLocale('全选')} 25 | 26 |
    27 | {selectValuesLength}/{leafListLength} 28 |
    29 |
    30 | ) 31 | } 32 | 33 | Bottom.propTypes = { 34 | checkedAll: PropTypes.bool.isRequired, 35 | onChange: PropTypes.func.isRequired, 36 | selectValuesLength: PropTypes.number.isRequired, 37 | leafListLength: PropTypes.number.isRequired, 38 | disabled: PropTypes.bool 39 | } 40 | 41 | export default Bottom 42 | -------------------------------------------------------------------------------- /src/component/tree/util.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | function getLeaf(list, result = []) { 4 | _.each(list, v => { 5 | if (v.children) { 6 | getLeaf(v.children, result) 7 | } else { 8 | result.push(v) 9 | } 10 | }) 11 | return result 12 | } 13 | 14 | function getUnLeafValues(list, result = []) { 15 | _.each(list, v => { 16 | if (v.children) { 17 | result.push(v.value) 18 | getUnLeafValues(v.children, result) 19 | } 20 | }) 21 | return result 22 | } 23 | 24 | // 过滤叶子 25 | function filterGroupListLeaf(list, what) { 26 | return _.filter(list, function(d) { 27 | if (d.children) { 28 | d.children = filterGroupListLeaf(d.children, what) 29 | } 30 | 31 | if (d.children) { 32 | return !!d.children.length 33 | } else { 34 | return what(d) 35 | } 36 | }) 37 | } 38 | 39 | function filterGroupList(list, what) { 40 | return filterGroupListLeaf(_.cloneDeep(list), what) 41 | } 42 | 43 | export { getLeaf, getUnLeafValues, filterGroupList } 44 | -------------------------------------------------------------------------------- /src/component/uploader/style.less: -------------------------------------------------------------------------------- 1 | .gm-uploader { 2 | display: inline-block; 3 | 4 | .gm-uploader-input[type='file'] { 5 | display: none; 6 | } 7 | 8 | .gm-uploader-default { 9 | width: 64px; 10 | height: 64px; 11 | font-size: 30px; 12 | border: 1px dashed fadeout(@gm-frame-border-color, 50%); 13 | border-radius: 4px; 14 | cursor: pointer; 15 | } 16 | 17 | &.disabled { 18 | cursor: not-allowed; 19 | 20 | .gm-uploader-default { 21 | .gm-disabled(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/component/uploader/uploader.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Uploader from './' 4 | import { observable } from 'mobx' 5 | 6 | const { DefaultImage } = Uploader 7 | 8 | const store = observable({ 9 | data: null, 10 | setData() { 11 | this.data = 12 | 'https://js.guanmai.cn/static_storage/json/common/logo/default/logo.pure.png' 13 | } 14 | }) 15 | 16 | storiesOf('Uploader', module) 17 | .add('default', () => ( 18 | console.log(files, e)} accept='image/*' /> 19 | )) 20 | .add('disabled', () => ( 21 | console.log(files, e)} 24 | accept='image/*' 25 | /> 26 | )) 27 | .add('自定义', () => ( 28 | console.log(files, e)} accept='.xlsx'> 29 | 30 | 31 | )) 32 | .add('+图片', () => ( 33 | console.log(files, e)} accept='image/*'> 34 | 35 | 36 | )) 37 | .add('+图片替换上传位置', () => ( 38 | store.setData()} accept='image/*'> 39 | 40 | {store.data && ( 41 | 48 | )} 49 | 50 | 51 | )) 52 | -------------------------------------------------------------------------------- /src/css/arrow.less: -------------------------------------------------------------------------------- 1 | .gm-arrow-down { 2 | position: absolute; 3 | content: " "; 4 | border-left: 5px solid transparent; 5 | border-right: 5px solid transparent; 6 | border-top: 5px solid @gm-color-third; 7 | display: block; 8 | width: 0; 9 | height: 0; 10 | top: 0; 11 | right: 5px; 12 | bottom: 0; 13 | margin: auto 0; 14 | } 15 | 16 | .gm-arrow-up { 17 | position: absolute; 18 | content: " "; 19 | border-left: 5px solid transparent; 20 | border-right: 5px solid transparent; 21 | border-bottom: 5px solid @gm-color-third; 22 | display: block; 23 | width: 0; 24 | height: 0; 25 | top: 0; 26 | right: 5px; 27 | bottom: 0; 28 | margin: auto 0; 29 | } 30 | 31 | .gm-arrow-right { 32 | position: absolute; 33 | content: " "; 34 | border-top: 5px solid transparent; 35 | border-bottom: 5px solid transparent; 36 | border-left: 5px solid @gm-color-third; 37 | display: block; 38 | width: 0; 39 | height: 0; 40 | top: 0; 41 | right: 5px; 42 | bottom: 0; 43 | margin: auto 0; 44 | 45 | &.active { 46 | border-left: 5px solid white; 47 | } 48 | } 49 | 50 | .GMArrowDown() { 51 | position: relative; 52 | 53 | &::after { 54 | .gm-arrow-down(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/css/bg.less: -------------------------------------------------------------------------------- 1 | // bg 2 | .gm-back-bg { 3 | background-color: @gm-back-body-bg !important; 4 | } 5 | 6 | .gm-bg { 7 | background-color: @body-bg !important; 8 | } 9 | 10 | .gm-bg-white { 11 | background: white !important; 12 | } 13 | 14 | .gm-bg-primary { 15 | background: @brand-primary !important; 16 | } 17 | 18 | .gm-bg-info { 19 | background-color: #d9edf7 !important; 20 | } 21 | 22 | .gm-bg-invalid { 23 | background-color: #ffd3cf !important; 24 | } 25 | 26 | .gm-bg-desc { 27 | background-color: @gm-color-fourth !important; 28 | } 29 | 30 | .gm-bg-error { 31 | background-color: @brand-danger !important; 32 | } 33 | 34 | .gm-bg-hover-primary:hover { 35 | color: @brand-primary !important; 36 | background: white !important; 37 | } 38 | 39 | .gm-bg-focus-primary:focus { 40 | color: @brand-primary !important; 41 | background: white !important; 42 | } 43 | 44 | .gm-bg-hover-focus-primary:hover, 45 | .gm-bg-hover-focus-primary:focus { 46 | color: @brand-primary !important; 47 | background: white !important; 48 | } 49 | 50 | .gm-hover-bg:hover { 51 | background-color: @gm-back-body-bg !important; 52 | } 53 | -------------------------------------------------------------------------------- /src/css/border.less: -------------------------------------------------------------------------------- 1 | // border 2 | .gm-border { 3 | border: 1px solid @gm-border-color !important; 4 | } 5 | 6 | .gm-border-0 { 7 | border: none !important; 8 | } 9 | 10 | .gm-border-top { 11 | border-top: 1px solid @gm-border-color !important; 12 | } 13 | 14 | .gm-border-right { 15 | border-right: 1px solid @gm-border-color !important; 16 | } 17 | 18 | .gm-border-bottom { 19 | border-bottom: 1px solid @gm-border-color !important; 20 | } 21 | 22 | .gm-border-left { 23 | border-left: 1px solid @gm-border-color !important; 24 | } 25 | 26 | .gm-border-top-0 { 27 | border-top: none !important; 28 | } 29 | 30 | .gm-border-right-0 { 31 | border-right: none !important; 32 | } 33 | 34 | .gm-border-bottom-0 { 35 | border-bottom: none !important; 36 | } 37 | 38 | .gm-border-left-0 { 39 | border-left: none !important; 40 | } 41 | -------------------------------------------------------------------------------- /src/css/cursor.less: -------------------------------------------------------------------------------- 1 | .gm-cursor { 2 | cursor: pointer; 3 | 4 | &[disabled] { 5 | cursor: not-allowed; 6 | } 7 | } 8 | 9 | .gm-not-allowed { 10 | cursor: not-allowed; 11 | } 12 | 13 | .gm-cursor-grab { 14 | cursor: grab; 15 | 16 | &[disabled] { 17 | cursor: not-allowed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/css/display.less: -------------------------------------------------------------------------------- 1 | // display 2 | .gm-block { 3 | display: block !important; 4 | } 5 | 6 | .gm-inline-block { 7 | display: inline-block !important; 8 | } 9 | 10 | .gm-inline { 11 | display: inline !important; 12 | } 13 | 14 | .gm-hidden { 15 | display: none !important; 16 | } 17 | -------------------------------------------------------------------------------- /src/css/error.less: -------------------------------------------------------------------------------- 1 | @import "variables.less"; 2 | 3 | .gm-has-error { 4 | color: @gm-error-text; 5 | 6 | // more select 7 | .gm-more-select-selected { 8 | border-color: @gm-error-border !important; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/css/overflow.less: -------------------------------------------------------------------------------- 1 | .gm-overflow { 2 | overflow: auto; 3 | } 4 | 5 | .gm-overflow-hidden { 6 | overflow: hidden; 7 | } 8 | 9 | .gm-overflow-x { 10 | overflow-x: auto; 11 | } 12 | 13 | .gm-overflow-x-hidden { 14 | overflow-x: hidden; 15 | } 16 | 17 | .gm-overflow-y { 18 | overflow-y: auto; 19 | } 20 | 21 | .gm-overflow-y-hidden { 22 | overflow-y: hidden; 23 | } 24 | -------------------------------------------------------------------------------- /src/css/position.less: -------------------------------------------------------------------------------- 1 | .gm-position-fixed { 2 | position: fixed; 3 | } 4 | 5 | .gm-position-absolute { 6 | position: absolute; 7 | } 8 | 9 | .gm-position-relative { 10 | position: relative; 11 | } 12 | -------------------------------------------------------------------------------- /src/css/rotate.less: -------------------------------------------------------------------------------- 1 | 2 | .gm-rotate-45 { 3 | transform: rotate(45deg); 4 | } 5 | 6 | .gm-rotate-90 { 7 | transform: rotate(90deg); 8 | } 9 | 10 | .gm-rotate-135 { 11 | transform: rotate(135deg); 12 | } 13 | 14 | .gm-rotate-180 { 15 | transform: rotate(180deg); 16 | } 17 | 18 | .gm-rotate-225 { 19 | transform: rotate(225deg); 20 | } 21 | 22 | .gm-rotate-270 { 23 | transform: rotate(270deg); 24 | } 25 | 26 | .gm-rotate-315 { 27 | transform: rotate(315deg); 28 | } 29 | -------------------------------------------------------------------------------- /src/css/shadow.less: -------------------------------------------------------------------------------- 1 | .gm-box-shadow-none { 2 | box-shadow: none !important; 3 | } 4 | 5 | .gm-box-shadow-bottom { 6 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) !important; 7 | } 8 | 9 | .gm-box-shadow-top { 10 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2) !important; 11 | } 12 | -------------------------------------------------------------------------------- /src/css/svg.less: -------------------------------------------------------------------------------- 1 | .gm-svg-icon { 2 | font-size: inherit; 3 | } 4 | 5 | .gm-svg-icon-spin { 6 | animation: icon-spin 2s infinite linear; 7 | display: inline-block; 8 | } 9 | 10 | .gm-svg-icon-stack { 11 | position: relative; 12 | display: inline-block; 13 | width: 2em; 14 | height: 2em; 15 | line-height: 2em; 16 | vertical-align: middle; 17 | } 18 | 19 | .gm-svg-icon-stack-1x, 20 | .gm-svg-icon-stack-2x { 21 | position: absolute; 22 | left: 0; 23 | width: 100%; 24 | text-align: center; 25 | } 26 | 27 | .gm-svg-icon-stack-1x { 28 | line-height: inherit; 29 | } 30 | 31 | .gm-svg-icon-stack-2x { 32 | font-size: 2em; 33 | } 34 | 35 | .gm-svg-icon-inverse { 36 | color: white; 37 | } 38 | 39 | .glyphicon-spin { 40 | animation: icon-spin 1000ms infinite linear; 41 | } 42 | 43 | @keyframes icon-spin { 44 | 0% { 45 | transform: rotate(0deg); 46 | } 47 | 48 | 100% { 49 | transform: rotate(359deg); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/css/variables.less: -------------------------------------------------------------------------------- 1 | // 私有 2 | 3 | @gm-back-body-bg: #f7f8fa; // 页面背景色 4 | 5 | // 规范颜色变量 6 | @gm-color-first: #000923; //左侧导航背景色、panel标题、页面正文文字 7 | @gm-color-second: rgba(36, 51, 81, 0.8); // 列表表头文字 8 | @gm-color-third: #8b92a3; // 二级导航标签文字 9 | @gm-color-fourth: #798294; // 默认输入框文字、备注、移动读数的背景色 10 | @gm-frame-border-color: #d8dee7; 11 | 12 | @gm-border-color: #d4d8d8; // 线条颜色,输入框线条、tab线条 13 | @gm-border-radius: 2px; 14 | 15 | @gm-list-bg-hover: #d7e8fc; // list hover颜色 16 | 17 | @gm-table-bg-accent: #f0f1f3; //表头背景 18 | 19 | @gm-color-white-first: #fff; 20 | @gm-color-white-second: darken(@gm-color-white-first, 40%); 21 | 22 | // disabled 23 | @gm-color-disabled: #eeeeee; 24 | 25 | // error 26 | @gm-error-border: #a94442; 27 | @gm-error-text: #a94442; 28 | 29 | // focus 用 30 | .gm-form-control-focus() { 31 | border-color: @brand-primary; 32 | } 33 | 34 | @gm-screen-sm: 768px; 35 | @gm-screen-md: 992px; 36 | @gm-screen-lg: 1200px; 37 | @gm-screen-xl: 1920px; 38 | 39 | @gm-screen-sm-min: @gm-screen-sm; 40 | @gm-screen-md-min: @gm-screen-md; 41 | @gm-screen-lg-min: @gm-screen-lg; 42 | @gm-screen-xl-min: @gm-screen-xl; 43 | 44 | @gm-screen-sm-max: @gm-screen-md - 1px; 45 | @gm-screen-md-max: @gm-screen-lg - 1px; 46 | @gm-screen-lg-max: @gm-screen-xl - 1px; 47 | 48 | // grid 49 | @gm-grid-columns: 24; 50 | -------------------------------------------------------------------------------- /src/demo.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | storiesOf('内部|demo', module).add('default', () => { 5 | return
    demo
    6 | }) 7 | -------------------------------------------------------------------------------- /src/deprecated/import_lead/style.less: -------------------------------------------------------------------------------- 1 | .gm-import-lead { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | .gm-import-lead table td input { 9 | width: 100%; 10 | border: none; 11 | background-color: transparent; 12 | } 13 | 14 | .gm-import-lead table td { 15 | padding: 0 !important; 16 | position: relative; 17 | } 18 | 19 | .gm-import-line { 20 | border: 1px solid #ddd; 21 | border-radius: 5px; 22 | padding: 5px; 23 | max-height: 60px; 24 | overflow-y: auto; 25 | margin-top: 5px; 26 | margin-bottom: 5px; 27 | } 28 | 29 | .gm-import-line div { 30 | float: left; 31 | width: 20px; 32 | height: 20px; 33 | border: 1px solid white; 34 | background-color: #f7f7f9; 35 | } 36 | 37 | .gm-import-line div.tip { 38 | background-color: #ffd3cf; 39 | } 40 | 41 | .gm-import-lead-content { 42 | flex: 1; 43 | overflow-y: auto; 44 | } 45 | 46 | .gm-import-lead .gm-import-lead-tip { 47 | display: none; 48 | position: absolute; 49 | z-index: 2; 50 | } 51 | 52 | .gm-import-lead table td:hover .gm-import-lead-tip { 53 | display: block; 54 | } 55 | -------------------------------------------------------------------------------- /src/deprecated/quick/index.js: -------------------------------------------------------------------------------- 1 | import QuickPanel from './quick_panel' 2 | import QuickFilter from './quick_filter' 3 | import QuickTab from './quick_tab' 4 | import QuickDesc from './quick_desc' 5 | import QuickDetail from './quick_detail' 6 | 7 | export { QuickPanel, QuickFilter, QuickTab, QuickDesc, QuickDetail } 8 | -------------------------------------------------------------------------------- /src/deprecated/search_select/filter.search.select.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import SearchSelect from './search.select' 4 | 5 | class FilterSearchSelect extends React.Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = { 9 | query: '' 10 | } 11 | this.handleSearch = ::this.handleSearch 12 | } 13 | 14 | handleSearch(query) { 15 | this.setState({ 16 | query 17 | }) 18 | } 19 | 20 | render() { 21 | const { list, onFilter, ...rest } = this.props 22 | 23 | const { query } = this.state 24 | let filterList = list 25 | if (query) { 26 | filterList = onFilter(filterList, query) 27 | } 28 | return ( 29 | 30 | ) 31 | } 32 | } 33 | 34 | FilterSearchSelect.propTypes = { 35 | disabled: PropTypes.bool, 36 | list: PropTypes.array.isRequired, 37 | isGroupList: PropTypes.bool, 38 | selected: PropTypes.any, 39 | onSelect: PropTypes.func.isRequired, 40 | onFilter: PropTypes.func.isRequired, 41 | delay: PropTypes.number, 42 | listMaxHeight: PropTypes.string, 43 | placeholder: PropTypes.string, 44 | isScrollToSelected: PropTypes.bool 45 | } 46 | 47 | export default FilterSearchSelect 48 | -------------------------------------------------------------------------------- /src/deprecated/tree_select/style.less: -------------------------------------------------------------------------------- 1 | .gm-tree-select { 2 | vertical-align: middle; 3 | background: white; 4 | 5 | .gm-tree-select-border { 6 | border-top: 1px solid #ddd; 7 | border-left: 1px solid #ddd; 8 | border-right: 1px solid #ddd; 9 | border-bottom: none; 10 | } 11 | 12 | .gm-tree-select-title { 13 | background-color: #eee; 14 | } 15 | 16 | .gm-tree-select-item { 17 | cursor: pointer; 18 | } 19 | 20 | .gm-tree-select-trap:hover { 21 | background-color: #eee; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/deprecated/trigger/style.less: -------------------------------------------------------------------------------- 1 | .gm-trigger { 2 | position: relative; 3 | // 默认arrow边框颜色 @gm-border-color 4 | // 默认arrow背景色 #FFF 5 | .gm-trigger-arrow { 6 | position: absolute; 7 | bottom: -11px; 8 | left: 10px; 9 | width: 0; 10 | height: 0; 11 | border-top: 4px solid transparent; 12 | border-right: 4px solid #fff; 13 | border-bottom: 4px solid #fff; 14 | border-left: 4px solid transparent; 15 | box-shadow: 1px 1px 0 @gm-border-color; 16 | transform: rotate(-135deg); 17 | z-index: 901; 18 | 19 | &.gm-trigger-arrow-top { 20 | position: absolute; 21 | top: -11px; 22 | transform: rotate(45deg); 23 | 24 | &.gm-trigger-arrow-right { 25 | position: absolute; 26 | top: -11px; 27 | transform: rotate(45deg); 28 | } 29 | } 30 | 31 | &.gm-trigger-arrow-right { 32 | position: absolute; 33 | left: auto; 34 | right: 10px; 35 | transform: rotate(-135deg); 36 | } 37 | } 38 | 39 | .gm-trigger-popup { 40 | position: absolute; 41 | top: 100%; 42 | margin-top: 6px; 43 | margin-bottom: 6px; 44 | left: 0; 45 | z-index: 900; 46 | } 47 | 48 | .gm-trigger-popup-no-arrow { 49 | margin-top: 3px; 50 | } 51 | 52 | .gm-trigger-popup-right { 53 | right: 0; 54 | left: auto; 55 | } 56 | 57 | .gm-trigger-popup-top { 58 | top: auto; 59 | bottom: 100%; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/event_type.js: -------------------------------------------------------------------------------- 1 | const GMEVENT = 'GM_EVENT_' 2 | 3 | const EVENT_TYPE = { 4 | DRAWER_SHOW: GMEVENT + 'DRAWER_SHOW', 5 | DRAWER_HIDE: GMEVENT + 'DRAWER_HIDE', 6 | MODAL_SHOW: GMEVENT + 'MODAL_SHOW', 7 | MODAL_HIDE: GMEVENT + 'MODAL_HIDE', 8 | DRAWER_SCROLL: GMEVENT + 'DRAWER_SCROLL', 9 | MODAL_SCROLL: GMEVENT + 'MODAL_SCROLL', 10 | BROWSER_SCROLL: GMEVENT + 'BROWSER_SCROLL', 11 | TABLE_SCROLL: GMEVENT + 'TABLE_SCROLL', 12 | FULL_LOADING_SHOW: GMEVENT + 'FULL_LOADING_SHOW', 13 | FULL_LOADING_HIDE: GMEVENT + 'FULL_LOADING_HIDE' 14 | } 15 | 16 | export default EVENT_TYPE 17 | -------------------------------------------------------------------------------- /src/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/src/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/src/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/src/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmfe/react-gm/62d5260e2ec1b75248b6fdc8339b7e5e3eeacb02/src/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/less/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "adjoining-classes": false, 3 | "box-sizing": false, 4 | "box-model": false, 5 | "compatible-vendor-prefixes": false, 6 | "floats": false, 7 | "font-sizes": false, 8 | "gradients": false, 9 | "important": false, 10 | "known-properties": false, 11 | "outline-none": false, 12 | "qualified-headings": false, 13 | "regex-selectors": false, 14 | "shorthand": false, 15 | "text-indent": false, 16 | "unique-headings": false, 17 | "universal-selector": false, 18 | "unqualified-attributes": false 19 | } 20 | -------------------------------------------------------------------------------- /src/less/badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Badges 3 | // -------------------------------------------------- 4 | 5 | // Base class 6 | .badge { 7 | display: inline-block; 8 | min-width: 10px; 9 | padding: 3px 7px; 10 | font-size: @font-size-small; 11 | font-weight: @badge-font-weight; 12 | color: @badge-color; 13 | line-height: @badge-line-height; 14 | vertical-align: middle; 15 | white-space: nowrap; 16 | text-align: center; 17 | background-color: @badge-bg; 18 | border-radius: @badge-border-radius; 19 | 20 | // Empty badges collapse automatically (not available in IE8) 21 | &:empty { 22 | display: none; 23 | } 24 | 25 | // Quick fix for badges in buttons 26 | .btn & { 27 | position: relative; 28 | top: -1px; 29 | } 30 | 31 | .btn-xs &, 32 | .btn-group-xs > .btn & { 33 | top: 0; 34 | padding: 1px 5px; 35 | } 36 | 37 | // Hover state, but only for links 38 | a& { 39 | &:hover, 40 | &:focus { 41 | color: @badge-link-hover-color; 42 | text-decoration: none; 43 | cursor: pointer; 44 | } 45 | } 46 | 47 | // Account for badges in navs 48 | .list-group-item.active > &, 49 | .nav-pills > .active > a > & { 50 | color: @badge-active-color; 51 | background-color: @badge-active-bg; 52 | } 53 | 54 | .list-group-item > & { 55 | float: right; 56 | } 57 | 58 | .list-group-item > & + & { 59 | margin-right: 5px; 60 | } 61 | 62 | .nav-pills > li > a > & { 63 | margin-left: 3px; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/less/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | .breadcrumb { 6 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; 7 | margin-bottom: @line-height-computed; 8 | list-style: none; 9 | background-color: @breadcrumb-bg; 10 | border-radius: @border-radius-base; 11 | 12 | > li { 13 | display: inline-block; 14 | 15 | + li:before { 16 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space 17 | padding: 0 5px; 18 | color: @breadcrumb-color; 19 | } 20 | } 21 | 22 | > .active { 23 | color: @breadcrumb-active-color; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/less/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | .close { 6 | float: right; 7 | font-size: (@font-size-base * 1.5); 8 | font-weight: @close-font-weight; 9 | line-height: 1; 10 | color: @close-color; 11 | text-shadow: @close-text-shadow; 12 | .opacity(.2); 13 | 14 | &:hover, 15 | &:focus { 16 | color: @close-color; 17 | text-decoration: none; 18 | cursor: pointer; 19 | .opacity(.5); 20 | } 21 | 22 | // Additional properties for button version 23 | // iOS requires the button element instead of an anchor tag. 24 | // If you want the anchor version, it requires `href="#"`. 25 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 26 | button& { 27 | padding: 0; 28 | cursor: pointer; 29 | background: transparent; 30 | border: 0; 31 | -webkit-appearance: none; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/less/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | // Heads up! 6 | // 7 | // We don't use the `.opacity()` mixin here since it causes a bug with text 8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. 9 | 10 | .fade { 11 | opacity: 0; 12 | .transition(opacity .15s linear); 13 | &.in { 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .collapse { 19 | display: none; 20 | 21 | &.in { 22 | display: block; 23 | } 24 | tr&.in { 25 | display: table-row; 26 | } 27 | tbody&.in { 28 | display: table-row-group; 29 | } 30 | } 31 | 32 | .collapsing { 33 | position: relative; 34 | height: 0; 35 | overflow: hidden; 36 | .transition-property(~"height, visibility"); 37 | .transition-duration(.35s); 38 | .transition-timing-function(ease); 39 | } 40 | -------------------------------------------------------------------------------- /src/less/custom.less: -------------------------------------------------------------------------------- 1 | // 以下变量将覆盖bootstrap的variable.less中的同名变量 2 | 3 | @font-size-base: 12px; 4 | @padding-base-vertical: 5px; 5 | @padding-base-horizontal: 10px; 6 | @line-height-base: 1.33; 7 | @border-radius-base: 3px; 8 | 9 | @gray-dark: #000923; 10 | 11 | @brand-primary: #56a3f2; 12 | @brand-danger: #fc887f; 13 | @brand-danger-hover: #d35147; 14 | 15 | @link-color: #1e80e5; 16 | @link-hover-color: darken(@link-color, 15%); 17 | 18 | @border-radius-base: 0; 19 | @border-radius-large: 0; 20 | @border-radius-small: 0; 21 | 22 | @btn-default-border: #d4d8d8; 23 | @input-border: #d4d8d8; 24 | @dropdown-fallback-border: #d4d8d8; 25 | @navbar-default-link-disabled-color: #d4d8d8; 26 | @popover-fallback-border-color: #d4d8d8; 27 | 28 | @input-border-focus: @brand-primary; 29 | 30 | @table-bg-accent: white; 31 | //** Background color used for `.table-hover` 和 `react-table`的hover 32 | @table-bg-hover: #b2d5ff; 33 | @input-color: @text-color; 34 | 35 | @input-color-placeholder: @gm-color-fourth; 36 | -------------------------------------------------------------------------------- /src/less/jumbotron.less: -------------------------------------------------------------------------------- 1 | // 2 | // Jumbotron 3 | // -------------------------------------------------- 4 | 5 | .jumbotron { 6 | padding-top: @jumbotron-padding; 7 | padding-bottom: @jumbotron-padding; 8 | margin-bottom: @jumbotron-padding; 9 | color: @jumbotron-color; 10 | background-color: @jumbotron-bg; 11 | 12 | h1, 13 | .h1 { 14 | color: @jumbotron-heading-color; 15 | } 16 | 17 | p { 18 | margin-bottom: (@jumbotron-padding / 2); 19 | font-size: @jumbotron-font-size; 20 | font-weight: 200; 21 | } 22 | 23 | > hr { 24 | border-top-color: darken(@jumbotron-bg, 10%); 25 | } 26 | 27 | .container &, 28 | .container-fluid & { 29 | border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container 30 | padding-left: (@grid-gutter-width / 2); 31 | padding-right: (@grid-gutter-width / 2); 32 | } 33 | 34 | .container { 35 | max-width: 100%; 36 | } 37 | 38 | @media screen and (min-width: @screen-sm-min) { 39 | padding-top: (@jumbotron-padding * 1.6); 40 | padding-bottom: (@jumbotron-padding * 1.6); 41 | 42 | .container &, 43 | .container-fluid & { 44 | padding-left: (@jumbotron-padding * 2); 45 | padding-right: (@jumbotron-padding * 2); 46 | } 47 | 48 | h1, 49 | .h1 { 50 | font-size: @jumbotron-heading-font-size; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/less/labels.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels 3 | // -------------------------------------------------- 4 | 5 | .label { 6 | display: inline; 7 | padding: .2em .6em .3em; 8 | font-size: 75%; 9 | font-weight: bold; 10 | line-height: 1; 11 | color: @label-color; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | border-radius: .25em; 16 | 17 | // Add hover effects, but only for links 18 | a& { 19 | &:hover, 20 | &:focus { 21 | color: @label-link-hover-color; 22 | text-decoration: none; 23 | cursor: pointer; 24 | } 25 | } 26 | 27 | // Empty labels collapse automatically (not available in IE8) 28 | &:empty { 29 | display: none; 30 | } 31 | 32 | // Quick fix for labels in buttons 33 | .btn & { 34 | position: relative; 35 | top: -1px; 36 | } 37 | } 38 | 39 | // Colors 40 | // Contextual variations (linked labels get darker on :hover) 41 | 42 | .label-default { 43 | .label-variant(@label-default-bg); 44 | } 45 | 46 | .label-primary { 47 | .label-variant(@label-primary-bg); 48 | } 49 | 50 | .label-success { 51 | .label-variant(@label-success-bg); 52 | } 53 | 54 | .label-info { 55 | .label-variant(@label-info-bg); 56 | } 57 | 58 | .label-warning { 59 | .label-variant(@label-warning-bg); 60 | } 61 | 62 | .label-danger { 63 | .label-variant(@label-danger-bg); 64 | } 65 | -------------------------------------------------------------------------------- /src/less/media.less: -------------------------------------------------------------------------------- 1 | .media { 2 | // Proper spacing between instances of .media 3 | margin-top: 15px; 4 | 5 | &:first-child { 6 | margin-top: 0; 7 | } 8 | } 9 | 10 | .media, 11 | .media-body { 12 | zoom: 1; 13 | overflow: hidden; 14 | } 15 | 16 | .media-body { 17 | width: 10000px; 18 | } 19 | 20 | .media-object { 21 | display: block; 22 | 23 | // Fix collapse in webkit from max-width: 100% and display: table-cell. 24 | &.img-thumbnail { 25 | max-width: none; 26 | } 27 | } 28 | 29 | .media-right, 30 | .media > .pull-right { 31 | padding-left: 10px; 32 | } 33 | 34 | .media-left, 35 | .media > .pull-left { 36 | padding-right: 10px; 37 | } 38 | 39 | .media-left, 40 | .media-right, 41 | .media-body { 42 | display: table-cell; 43 | vertical-align: top; 44 | } 45 | 46 | .media-middle { 47 | vertical-align: middle; 48 | } 49 | 50 | .media-bottom { 51 | vertical-align: bottom; 52 | } 53 | 54 | // Reset margins on headings for tighter default spacing 55 | .media-heading { 56 | margin-top: 0; 57 | margin-bottom: 5px; 58 | } 59 | 60 | // Media list variation 61 | // 62 | // Undo default ul/ol styles 63 | .media-list { 64 | padding-left: 0; 65 | list-style: none; 66 | } 67 | -------------------------------------------------------------------------------- /src/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------------------------------- 3 | // Utilities 4 | @import "mixins/hide-text.less"; 5 | @import "mixins/opacity.less"; 6 | @import "mixins/image.less"; 7 | @import "mixins/labels.less"; 8 | @import "mixins/reset-filter.less"; 9 | @import "mixins/resize.less"; 10 | @import "mixins/responsive-visibility.less"; 11 | @import "mixins/size.less"; 12 | @import "mixins/tab-focus.less"; 13 | @import "mixins/reset-text.less"; 14 | @import "mixins/text-emphasis.less"; 15 | @import "mixins/text-overflow.less"; 16 | @import "mixins/vendor-prefixes.less"; 17 | // Components 18 | @import "mixins/alerts.less"; 19 | @import "mixins/buttons.less"; 20 | @import "mixins/panels.less"; 21 | @import "mixins/pagination.less"; 22 | @import "mixins/list-group.less"; 23 | @import "mixins/nav-divider.less"; 24 | @import "mixins/forms.less"; 25 | @import "mixins/progress-bar.less"; 26 | @import "mixins/table-row.less"; 27 | // Skins 28 | @import "mixins/background-variant.less"; 29 | @import "mixins/border-radius.less"; 30 | @import "mixins/gradients.less"; 31 | // Layout 32 | @import "mixins/clearfix.less"; 33 | @import "mixins/center-block.less"; 34 | @import "mixins/nav-vertical-align.less"; 35 | @import "mixins/grid-framework.less"; 36 | @import "mixins/grid.less"; 37 | -------------------------------------------------------------------------------- /src/less/mixins/alerts.less: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | .alert-variant(@background; @border; @text-color) { 4 | background-color: @background; 5 | border-color: @border; 6 | color: @text-color; 7 | 8 | hr { 9 | border-top-color: darken(@border, 5%); 10 | } 11 | .alert-link { 12 | color: darken(@text-color, 10%); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/less/mixins/background-variant.less: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | .bg-variant(@color) { 4 | background-color: @color; 5 | a&:hover, 6 | a&:focus { 7 | background-color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/less/mixins/border-radius.less: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | .border-top-radius(@radius) { 4 | border-top-right-radius: @radius; 5 | border-top-left-radius: @radius; 6 | } 7 | 8 | .border-right-radius(@radius) { 9 | border-bottom-right-radius: @radius; 10 | border-top-right-radius: @radius; 11 | } 12 | 13 | .border-bottom-radius(@radius) { 14 | border-bottom-right-radius: @radius; 15 | border-bottom-left-radius: @radius; 16 | } 17 | 18 | .border-left-radius(@radius) { 19 | border-bottom-left-radius: @radius; 20 | border-top-left-radius: @radius; 21 | } 22 | -------------------------------------------------------------------------------- /src/less/mixins/center-block.less: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | .center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /src/less/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | .clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/less/mixins/hide-text.less: -------------------------------------------------------------------------------- 1 | // CSS image replacement 2 | // 3 | // Heads up! v3 launched with only `.hide-text()`, but per our pattern for 4 | // mixins being reused as classes with the same name, this doesn't hold up. As 5 | // of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. 6 | // 7 | // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 8 | 9 | // Deprecated as of v3.0.1 (has been removed in v4) 10 | .hide-text() { 11 | font: ~"0/0" a; 12 | color: transparent; 13 | text-shadow: none; 14 | background-color: transparent; 15 | border: 0; 16 | } 17 | 18 | // New mixin to use as of v3.0.1 19 | .text-hide() { 20 | .hide-text(); 21 | } 22 | -------------------------------------------------------------------------------- /src/less/mixins/image.less: -------------------------------------------------------------------------------- 1 | // Image Mixins 2 | // - Responsive image 3 | // - Retina image 4 | 5 | // Responsive image 6 | // 7 | // Keep images from scaling beyond the width of their parents. 8 | .img-responsive(@display: block) { 9 | display: @display; 10 | max-width: 100%; // Part 1: Set a maximum relative to the parent 11 | height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching 12 | } 13 | 14 | // Retina image 15 | // 16 | // Short retina mixin for setting background-image and -size. Note that the 17 | // spelling of `min--moz-device-pixel-ratio` is intentional. 18 | .img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { 19 | background-image: url("@{file-1x}"); 20 | 21 | @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and ( min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx) { 22 | background-image: url("@{file-2x}"); 23 | background-size: @width-1x @height-1x; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/less/mixins/labels.less: -------------------------------------------------------------------------------- 1 | // Labels 2 | 3 | .label-variant(@color) { 4 | background-color: @color; 5 | 6 | &[href] { 7 | &:hover, 8 | &:focus { 9 | background-color: darken(@color, 10%); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/less/mixins/list-group.less: -------------------------------------------------------------------------------- 1 | // List Groups 2 | 3 | .list-group-item-variant(@state; @background; @color) { 4 | .list-group-item-@{state} { 5 | color: @color; 6 | background-color: @background; 7 | 8 | a&, 9 | button& { 10 | color: @color; 11 | 12 | .list-group-item-heading { 13 | color: inherit; 14 | } 15 | 16 | &:hover, 17 | &:focus { 18 | color: @color; 19 | background-color: darken(@background, 5%); 20 | } 21 | &.active, 22 | &.active:hover, 23 | &.active:focus { 24 | color: #fff; 25 | background-color: @color; 26 | border-color: @color; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/less/mixins/nav-divider.less: -------------------------------------------------------------------------------- 1 | // Horizontal dividers 2 | // 3 | // Dividers (basically an hr) within dropdowns and nav lists 4 | 5 | .nav-divider(@color: #e5e5e5) { 6 | height: 1px; 7 | margin: ((@line-height-computed / 2) - 1) 0; 8 | overflow: hidden; 9 | background-color: @color; 10 | } 11 | -------------------------------------------------------------------------------- /src/less/mixins/nav-vertical-align.less: -------------------------------------------------------------------------------- 1 | // Navbar vertical align 2 | // 3 | // Vertically center elements in the navbar. 4 | // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. 5 | 6 | .navbar-vertical-align(@element-height) { 7 | margin-top: ((@navbar-height - @element-height) / 2); 8 | margin-bottom: ((@navbar-height - @element-height) / 2); 9 | } 10 | -------------------------------------------------------------------------------- /src/less/mixins/opacity.less: -------------------------------------------------------------------------------- 1 | // Opacity 2 | 3 | .opacity(@opacity) { 4 | opacity: @opacity; 5 | // IE8 filter 6 | @opacity-ie: (@opacity * 100); 7 | filter: ~"alpha(opacity=@{opacity-ie})"; 8 | } 9 | -------------------------------------------------------------------------------- /src/less/mixins/pagination.less: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | .pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 4 | > li { 5 | > a, 6 | > span { 7 | padding: @padding-vertical @padding-horizontal; 8 | font-size: @font-size; 9 | line-height: @line-height; 10 | } 11 | &:first-child { 12 | > a, 13 | > span { 14 | .border-left-radius(@border-radius); 15 | } 16 | } 17 | &:last-child { 18 | > a, 19 | > span { 20 | .border-right-radius(@border-radius); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/less/mixins/panels.less: -------------------------------------------------------------------------------- 1 | // Panels 2 | 3 | .panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { 4 | border-color: @border; 5 | 6 | & > .panel-heading { 7 | color: @heading-text-color; 8 | background-color: @heading-bg-color; 9 | border-color: @heading-border; 10 | 11 | + .panel-collapse > .panel-body { 12 | border-top-color: @border; 13 | } 14 | .badge { 15 | color: @heading-bg-color; 16 | background-color: @heading-text-color; 17 | } 18 | } 19 | & > .panel-footer { 20 | + .panel-collapse > .panel-body { 21 | border-bottom-color: @border; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/less/mixins/progress-bar.less: -------------------------------------------------------------------------------- 1 | // Progress bars 2 | 3 | .progress-bar-variant(@color) { 4 | background-color: @color; 5 | 6 | // Deprecated parent class requirement as of v3.2.0 7 | .progress-striped & { 8 | #gradient > .striped(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/less/mixins/reset-filter.less: -------------------------------------------------------------------------------- 1 | // Reset filters for IE 2 | // 3 | // When you need to remove a gradient background, do not forget to use this to reset 4 | // the IE filter for IE9 and below. 5 | 6 | .reset-filter() { 7 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); 8 | } 9 | -------------------------------------------------------------------------------- /src/less/mixins/reset-text.less: -------------------------------------------------------------------------------- 1 | .reset-text() { 2 | font-family: @font-family-base; 3 | // We deliberately do NOT reset font-size. 4 | font-style: normal; 5 | font-weight: normal; 6 | letter-spacing: normal; 7 | line-break: auto; 8 | line-height: @line-height-base; 9 | text-align: left; // Fallback for where `start` is not supported 10 | text-align: start; 11 | text-decoration: none; 12 | text-shadow: none; 13 | text-transform: none; 14 | white-space: normal; 15 | word-break: normal; 16 | word-spacing: normal; 17 | word-wrap: normal; 18 | } 19 | -------------------------------------------------------------------------------- /src/less/mixins/resize.less: -------------------------------------------------------------------------------- 1 | // Resize anything 2 | 3 | .resizable(@direction) { 4 | resize: @direction; // Options: horizontal, vertical, both 5 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` 6 | } 7 | -------------------------------------------------------------------------------- /src/less/mixins/responsive-visibility.less: -------------------------------------------------------------------------------- 1 | // Responsive utilities 2 | 3 | // 4 | // More easily include all the states for responsive-utilities.less. 5 | .responsive-visibility() { 6 | display: block !important; 7 | table& { 8 | display: table !important; 9 | } 10 | tr& { 11 | display: table-row !important; 12 | } 13 | th&, 14 | td& { 15 | display: table-cell !important; 16 | } 17 | } 18 | 19 | .responsive-invisibility() { 20 | display: none !important; 21 | } 22 | -------------------------------------------------------------------------------- /src/less/mixins/size.less: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | .size(@width; @height) { 4 | width: @width; 5 | height: @height; 6 | } 7 | 8 | .square(@size) { 9 | .size(@size; @size); 10 | } 11 | -------------------------------------------------------------------------------- /src/less/mixins/tab-focus.less: -------------------------------------------------------------------------------- 1 | // WebKit-style focus 2 | 3 | .tab-focus() { 4 | // Default 5 | outline: thin dotted; 6 | // WebKit 7 | outline: 5px auto -webkit-focus-ring-color; 8 | outline-offset: -2px; 9 | } 10 | -------------------------------------------------------------------------------- /src/less/mixins/table-row.less: -------------------------------------------------------------------------------- 1 | // Tables 2 | 3 | .table-row-variant(@state; @background) { 4 | // Exact selectors below required to override `.table-striped` and prevent 5 | // inheritance to nested tables. 6 | .table > thead > tr, 7 | .table > tbody > tr, 8 | .table > tfoot > tr { 9 | > td.@{state}, 10 | > th.@{state}, 11 | &.@{state} > td, 12 | &.@{state} > th { 13 | background-color: @background; 14 | } 15 | } 16 | 17 | // Hover states for `.table-hover` 18 | // Note: this is not available for cells or rows within `thead` or `tfoot`. 19 | .table-hover > tbody > tr { 20 | > td.@{state}:hover, 21 | > th.@{state}:hover, 22 | &.@{state}:hover > td, 23 | &:hover > .@{state}, 24 | &.@{state}:hover > th { 25 | background-color: darken(@background, 5%); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/less/mixins/text-emphasis.less: -------------------------------------------------------------------------------- 1 | // Typography 2 | 3 | .text-emphasis-variant(@color) { 4 | color: @color; 5 | a&:hover, 6 | a&:focus { 7 | color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/less/mixins/text-overflow.less: -------------------------------------------------------------------------------- 1 | // Text overflow 2 | // Requires inline-block or block for proper styling 3 | 4 | .text-overflow() { 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } 9 | -------------------------------------------------------------------------------- /src/less/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | .pager { 6 | padding-left: 0; 7 | margin: @line-height-computed 0; 8 | list-style: none; 9 | text-align: center; 10 | &:extend(.clearfix all); 11 | li { 12 | display: inline; 13 | > a, 14 | > span { 15 | display: inline-block; 16 | padding: 5px 14px; 17 | background-color: @pager-bg; 18 | border: 1px solid @pager-border; 19 | border-radius: @pager-border-radius; 20 | } 21 | 22 | > a:hover, 23 | > a:focus { 24 | text-decoration: none; 25 | background-color: @pager-hover-bg; 26 | } 27 | } 28 | 29 | .next { 30 | > a, 31 | > span { 32 | float: right; 33 | } 34 | } 35 | 36 | .previous { 37 | > a, 38 | > span { 39 | float: left; 40 | } 41 | } 42 | 43 | .disabled { 44 | > a, 45 | > a:hover, 46 | > a:focus, 47 | > span { 48 | color: @pager-disabled-color; 49 | background-color: @pager-bg; 50 | cursor: @cursor-disabled; 51 | pointer-events: none; // Future-proof disabling of clicks on `` elements 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/less/responsive-embed.less: -------------------------------------------------------------------------------- 1 | // Embeds responsive 2 | // 3 | // Credit: Nicolas Gallagher and SUIT CSS. 4 | 5 | .embed-responsive { 6 | position: relative; 7 | display: block; 8 | height: 0; 9 | padding: 0; 10 | overflow: hidden; 11 | 12 | .embed-responsive-item, 13 | iframe, 14 | embed, 15 | object, 16 | video { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | bottom: 0; 21 | height: 100%; 22 | width: 100%; 23 | border: 0; 24 | } 25 | } 26 | 27 | // Modifier class for 16:9 aspect ratio 28 | .embed-responsive-16by9 { 29 | padding-bottom: 56.25%; 30 | } 31 | 32 | // Modifier class for 4:3 aspect ratio 33 | .embed-responsive-4by3 { 34 | padding-bottom: 75%; 35 | } 36 | -------------------------------------------------------------------------------- /src/less/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | // Mixin and adjust the regular image class 6 | .thumbnail { 7 | display: block; 8 | padding: @thumbnail-padding; 9 | margin-bottom: @line-height-computed; 10 | line-height: @line-height-base; 11 | background-color: @thumbnail-bg; 12 | border: 1px solid @thumbnail-border; 13 | border-radius: @thumbnail-border-radius; 14 | .transition(border .2s ease-in-out); 15 | 16 | > img, 17 | a > img { 18 | &:extend(.img-responsive); 19 | margin-left: auto; 20 | margin-right: auto; 21 | } 22 | 23 | // Add a hover state for linked versions only 24 | a&:hover, 25 | a&:focus, 26 | a&.active { 27 | border-color: @link-color; 28 | } 29 | 30 | // Image captions 31 | .caption { 32 | padding: @thumbnail-caption-padding; 33 | color: @thumbnail-caption-color; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/less/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | // Floats 6 | // ------------------------- 7 | 8 | .clearfix { 9 | .clearfix(); 10 | } 11 | 12 | .center-block { 13 | .center-block(); 14 | } 15 | 16 | .pull-right { 17 | float: right !important; 18 | } 19 | 20 | .pull-left { 21 | float: left !important; 22 | } 23 | 24 | // Toggling content 25 | // ------------------------- 26 | 27 | // Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 28 | .hide { 29 | display: none !important; 30 | } 31 | 32 | .show { 33 | display: block !important; 34 | } 35 | 36 | .invisible { 37 | visibility: hidden; 38 | } 39 | 40 | .text-hide { 41 | .text-hide(); 42 | } 43 | 44 | // Hide from screenreaders and browsers 45 | // 46 | // Credit: HTML5 Boilerplate 47 | 48 | .hidden { 49 | display: none !important; 50 | } 51 | 52 | // For Affix plugin 53 | // ------------------------- 54 | 55 | .affix { 56 | position: fixed; 57 | } 58 | -------------------------------------------------------------------------------- /src/less/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | // Base class 6 | .well { 7 | min-height: 20px; 8 | padding: 19px; 9 | margin-bottom: 20px; 10 | background-color: @well-bg; 11 | border: 1px solid @well-border; 12 | border-radius: @border-radius-base; 13 | .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .05)); 14 | blockquote { 15 | border-color: #ddd; 16 | border-color: rgba(0, 0, 0, .15); 17 | } 18 | } 19 | 20 | // Sizes 21 | .well-lg { 22 | padding: 24px; 23 | border-radius: @border-radius-large; 24 | } 25 | 26 | .well-sm { 27 | padding: 9px; 28 | border-radius: @border-radius-small; 29 | } 30 | -------------------------------------------------------------------------------- /src/locales.js: -------------------------------------------------------------------------------- 1 | export { setLocale, getLocale } from '../locales' 2 | -------------------------------------------------------------------------------- /src/other.less: -------------------------------------------------------------------------------- 1 | .gm-invalid { 2 | border-color: #a94442 !important; 3 | } 4 | 5 | .gm-filter-blur { 6 | filter: blur(2px); 7 | } 8 | 9 | .gm-filter-blur-transition { 10 | filter: blur(2px); 11 | transition: 0.3s filter; 12 | } 13 | 14 | .gm-no-outline { 15 | outline: none; 16 | } 17 | -------------------------------------------------------------------------------- /src/sotries.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | storiesOf('some', module) 5 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import hoistStatics from 'hoist-non-react-statics' 3 | 4 | const withDeprecated = warnText => { 5 | return Component => { 6 | const Deprecated = props => { 7 | useEffect(() => { 8 | console.warn(warnText || 'Deprecated') 9 | }, []) 10 | return 11 | } 12 | 13 | return hoistStatics(Deprecated, Component) 14 | } 15 | } 16 | 17 | const warn = function() { 18 | if (process.env.NODE_ENV === 'production') { 19 | return 20 | } 21 | console.warn.apply(this, ['[react-gm warn] ', ...arguments]) 22 | } 23 | 24 | const devWarnForHook = callback => { 25 | devWarn(() => { 26 | useEffect(() => { 27 | callback() 28 | }, []) 29 | }) 30 | } 31 | 32 | const devWarn = callback => { 33 | if (process.env.NODE_ENV !== 'production') { 34 | callback() 35 | } 36 | } 37 | 38 | export { withDeprecated, warn, devWarn, devWarnForHook } 39 | -------------------------------------------------------------------------------- /src/validator/index.js: -------------------------------------------------------------------------------- 1 | import Validator from './validator' 2 | // 初始化默认的规则 3 | import './rules' 4 | import TYPE from './type' 5 | 6 | Object.assign(Validator, { 7 | TYPE 8 | }) 9 | 10 | export default Validator 11 | -------------------------------------------------------------------------------- /src/validator/type.js: -------------------------------------------------------------------------------- 1 | const TYPE = { 2 | required: 'required', 3 | email: 'email', 4 | url: 'url', 5 | number: 'number', 6 | number_positive: 'number_positive', 7 | number_or_letter: 'number_or_letter' 8 | } 9 | 10 | export default TYPE 11 | -------------------------------------------------------------------------------- /src/var.less: -------------------------------------------------------------------------------- 1 | @import "../src/less/variables.less"; // bootstrap 变量 2 | @import "../src/less/mixins.less"; // bootstrap 样式 3 | @import "../src/less/custom.less"; // 覆盖bootstrap 变量 4 | @import "../src/css/variables.less"; // 自定义 5 | -------------------------------------------------------------------------------- /svg/calendar-month.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /svg/calendar-year.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /svg/calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 12 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /svg/check-detail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /svg/close-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /svg/closeup.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /svg/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svg/down-small.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/down.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/edit-box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /svg/edit-pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /svg/fun.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/left-small.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/minus-square.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svg/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /svg/ok.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /svg/plus-square.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/right-small.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/setting.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /svg/success-circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/up-small.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /svg/up.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /table/cell.less: -------------------------------------------------------------------------------- 1 | // 1920x1080的尺寸是12px;1260x768的尺寸是8px;768x1024(ipad)尺寸是2px。 2 | 3 | .gm-react-edit-table-cell-padding { 4 | padding-left: 2px; 5 | padding-right: 2px; 6 | 7 | @media (min-width: 768px) { 8 | padding-left: 8px; 9 | padding-right: 8px; 10 | } 11 | 12 | @media (min-width: 1260px) { 13 | padding-left: 12px; 14 | padding-right: 12px; 15 | } 16 | } 17 | 18 | .gm-react-edit-table-common-input { 19 | width: 100%; 20 | outline: none; 21 | border-width: 1px; 22 | border-style: solid; 23 | padding-left: 8px; 24 | padding-right: 8px; 25 | box-sizing: border-box; 26 | height: 32px; 27 | line-height: 32px; 28 | border-color: #d4d7e9; 29 | border-radius: 2px; 30 | 31 | &:hover { 32 | border-color: @brand-primary; 33 | box-shadow: 0 0 0 1px @brand-primary; 34 | } 35 | 36 | &:focus { 37 | border-color: @brand-primary; 38 | box-shadow: 0 0 0 1px @brand-primary; 39 | } 40 | 41 | &.gm-popover-active { 42 | border-color: @brand-primary; 43 | box-shadow: 0 0 0 1px @brand-primary; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /table/edit/edit_table.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classNames from 'classnames' 3 | import Table from '../table' 4 | 5 | const EditTable = props => { 6 | const { className, ...rest } = props 7 | return ( 8 | 9 | ) 10 | } 11 | 12 | EditTable.propTypes = { 13 | ...Table.propTypes 14 | } 15 | 16 | export default EditTable 17 | -------------------------------------------------------------------------------- /table/hoc/diy_table/sort_list.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import SVGRemove from '../../../svg/remove.svg' 4 | 5 | const SortList = ({ cols, onColsRemove }) => { 6 | const onRemove = (key, e) => { 7 | e.stopPropagation() 8 | onColsRemove(key) 9 | } 10 | 11 | return ( 12 |
      13 | {cols.map(item => { 14 | const { diyItemText, Header, key, diyEnable } = item 15 | const text = diyItemText || Header 16 | return ( 17 |
    • 18 | {text} 19 | {diyEnable && ( 20 | 24 | )} 25 |
    • 26 | ) 27 | })} 28 |
    29 | ) 30 | } 31 | 32 | SortList.propTypes = { 33 | cols: PropTypes.array.isRequired, 34 | // onColsChange: PropTypes.func.isRequired, 35 | onColsRemove: PropTypes.func.isRequired 36 | } 37 | 38 | export default SortList 39 | -------------------------------------------------------------------------------- /table/hoc/fixed_first_columns_table.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Table from '../table' 4 | 5 | // 固定第一列,默认用来固定 select table 第一列 6 | function fixedFirstColumnsTableHOC(Component) { 7 | const FixedFirstColumnsTable = props => { 8 | const { columns, firstColumnWidth, ...rest } = props 9 | 10 | const newColumns = [ 11 | { ...columns[0], fixed: 'left', width: firstColumnWidth }, 12 | ...columns.slice(1) 13 | ] 14 | 15 | return 16 | } 17 | 18 | FixedFirstColumnsTable.propTypes = { 19 | ...Table.propTypes, 20 | columns: PropTypes.array.isRequired, 21 | firstColumnWidth: PropTypes.number 22 | } 23 | 24 | FixedFirstColumnsTable.defaultProps = { 25 | firstColumnWidth: 40 26 | } 27 | 28 | return FixedFirstColumnsTable 29 | } 30 | 31 | export default fixedFirstColumnsTableHOC 32 | -------------------------------------------------------------------------------- /table/hoc/sub_table.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react' 2 | import Table from '../table' 3 | import classNames from 'classnames' 4 | import { referOfWidth } from '../util' 5 | 6 | const subTableHOC = Component => { 7 | const SubTable = forwardRef((props, ref) => { 8 | const { columns, className, ...rest } = props 9 | return ( 10 | null, // 只是用来占据空间 19 | filterable: false, 20 | sortable: false, 21 | resizable: false 22 | }, 23 | ...columns 24 | ]} 25 | className={classNames('gm-react-sub-table', className)} 26 | /> 27 | ) 28 | }) 29 | 30 | SubTable.propTypes = { 31 | ...Table.propTypes 32 | } 33 | 34 | return SubTable 35 | } 36 | 37 | export default subTableHOC 38 | -------------------------------------------------------------------------------- /table/index.js: -------------------------------------------------------------------------------- 1 | import Table from './table' 2 | 3 | import EditTable from './edit/edit_table' 4 | 5 | import fixedColumnsTableHOC from './hoc/fixed_columns_table' 6 | import fixedFirstColumnsTableHOC from './hoc/fixed_first_columns_table' 7 | import selectTableV2HOC from './hoc/select_table' 8 | import expandTableHOC from './hoc/expand_table' 9 | import diyTableHOC from './hoc/diy_table' 10 | import subTableHOC from './hoc/sub_table' 11 | 12 | import BatchActionBar from './hoc/select_table/batch_action_bar' 13 | 14 | // 只暴露些方法 15 | import { 16 | OperationHeader, 17 | OperationDelete, 18 | OperationDetail, 19 | OperationCell, 20 | OperationRowEdit, 21 | SortHeader, 22 | EditTableOperation, 23 | EditContentInputNumber, 24 | EditContentInput, 25 | referOfWidth, 26 | EditButton 27 | } from './util' 28 | 29 | const TableUtil = { 30 | OperationHeader, 31 | OperationDelete, 32 | OperationDetail, 33 | OperationCell, 34 | OperationRowEdit, 35 | SortHeader, 36 | EditTableOperation, 37 | EditContentInputNumber, 38 | EditContentInput, 39 | EditButton, 40 | referOfWidth, 41 | BatchActionBar 42 | } 43 | 44 | export { 45 | Table, 46 | EditTable, 47 | subTableHOC, 48 | diyTableHOC, 49 | fixedColumnsTableHOC, 50 | fixedFirstColumnsTableHOC, 51 | selectTableV2HOC, 52 | expandTableHOC, 53 | TableUtil 54 | } 55 | -------------------------------------------------------------------------------- /table/table/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './base' 2 | -------------------------------------------------------------------------------- /table_x/README.md: -------------------------------------------------------------------------------- 1 | ## tableX 踩的坑,阅读后改代码更自信 2 | 3 | - 注意不要随意升级版本,目前使用 7.0.0-rc.11 4 | - 7.0.0-rc.11 天然不支持 column.show, 所以自行实现了 column.show 的支持.[issue](https://github.com/tannerlinsley/react-table/issues/1665) 5 | - defaultColumn 的值不要轻易改动,具体看代码。目前实现了 minWidth,width,maxWidth 逻辑与 v6 一致,且需语义一致。 6 | - 使用 useResizeColumns 后,无法兼容到 v6 的 minWidth,width,maxWidth 的实现,所以去掉了 useResizeColumns 7 | - 斑马线,不能用 css 的 `:even` 和 `:odd` 实现。因为在使用虚拟列表的时候有坑。 8 | - 使用.gm-table-x-td 定义 background 是有原因的,比如 使用 fixedColumnHOC 时候的背景穿透问题 9 | - 虚拟列表的实现是 copy 了一份 TableX,请保证一致 10 | - 改动需要考虑 keyboard 那边 11 | - keyboard 测试 向上下左右是否有问题,特别是不在显示区域的是否可以滚动到显示区域 12 | - keyboard 新增一行的性能,行数很大的时候的性能 13 | - keyboard 的 input 不会因为新增而换掉 dom。即 控制台打出该 dom,在新增后 hover 到控制台的 dom 还能找到 14 | -------------------------------------------------------------------------------- /table_x/base/td.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { getColumnStyle } from '../util' 3 | import PropTypes from 'prop-types' 4 | import React from 'react' 5 | 6 | const Td = ({ cell, totalWidth }) => { 7 | const cp = cell.getCellProps() 8 | const tdProps = { 9 | ...cp, 10 | className: classNames('gm-table-x-td', { 11 | 'gm-table-x-fixed-left': cell.column.fixed === 'left', 12 | 'gm-table-x-fixed-right': cell.column.fixed === 'right' 13 | }), 14 | style: { 15 | ...cp.style, 16 | ...getColumnStyle(cell.column) 17 | } 18 | } 19 | 20 | if (cell.column.fixed === 'left') { 21 | // 用到 fixed,可以利用 totalLeft 22 | tdProps.style.left = cell.column.totalLeft 23 | } else if (cell.column.fixed === 'right') { 24 | tdProps.style.right = 25 | totalWidth - cell.column.totalLeft - cell.column.totalWidth 26 | } 27 | 28 | return
    {cell.render('Cell')}
    29 | } 30 | 31 | Td.whyDidYouRender = true 32 | 33 | Td.propTypes = { 34 | cell: PropTypes.object.isRequired, 35 | totalWidth: PropTypes.number.isRequired 36 | } 37 | 38 | export default React.memo(Td) 39 | -------------------------------------------------------------------------------- /table_x/base/th.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { getColumnStyle, SortHeader } from '../util' 3 | import PropTypes from 'prop-types' 4 | import React from 'react' 5 | 6 | const Th = ({ column, totalWidth }) => { 7 | const hp = column.getHeaderProps() 8 | 9 | const thProps = { 10 | ...hp, 11 | className: classNames('gm-table-x-th', hp.className, { 12 | 'gm-table-x-fixed-left': column.fixed === 'left', 13 | 'gm-table-x-fixed-right': column.fixed === 'right' 14 | }), 15 | style: { 16 | ...hp.style, 17 | ...getColumnStyle(column) 18 | } 19 | } 20 | 21 | if (column.fixed === 'left') { 22 | thProps.style.left = column.totalLeft 23 | } else if (column.fixed === 'right') { 24 | thProps.style.right = totalWidth - column.totalLeft - column.totalWidth 25 | } 26 | 27 | return ( 28 |
    29 |
    30 | {column.render('Header')} 31 | {column.canSort && ( 32 | 38 | )} 39 |
    40 |
    41 | ) 42 | } 43 | 44 | Th.whyDidYouRender = true 45 | 46 | Th.propTypes = { 47 | column: PropTypes.object.isRequired, 48 | totalWidth: PropTypes.number.isRequired 49 | } 50 | 51 | export default React.memo(Th) 52 | -------------------------------------------------------------------------------- /table_x/base/thead.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import Th from './th' 4 | 5 | const THead = ({ headerGroups, totalWidth }) => { 6 | return ( 7 |
    8 | {headerGroups.map((headerGroup, i) => ( 9 |
    10 | {headerGroup.headers.map((column, i) => ( 11 |
    12 | ))} 13 | 14 | ))} 15 | 16 | ) 17 | } 18 | 19 | THead.whyDidYouRender = true 20 | 21 | THead.propTypes = { 22 | headerGroups: PropTypes.array.isRequired, 23 | totalWidth: PropTypes.number.isRequired 24 | } 25 | 26 | export default React.memo(THead) 27 | -------------------------------------------------------------------------------- /table_x/base/tr.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import PropTypes from 'prop-types' 3 | import React from 'react' 4 | import Td from './td' 5 | 6 | const Tr = ({ 7 | row, 8 | SubComponent, 9 | keyField, 10 | style, 11 | totalWidth, 12 | isTrDisable 13 | }) => { 14 | const gp = row.getRowProps() 15 | 16 | const props = { 17 | ...gp, 18 | className: classNames('gm-table-x-tr', { 19 | 'gm-table-x-tr-disable': isTrDisable(row.original, row.index), 20 | 'gm-table-x-tr-odd': row.index % 2 === 0, 21 | 'gm-table-x-tr-even': row.index % 2 !== 0 22 | }) 23 | } 24 | 25 | // 目前视为了 sortable 用。值可能是 undefined,keyField 没作用的情况 26 | const dataId = row.original[keyField] 27 | 28 | return ( 29 |
    30 |
    31 | {row.cells.map((cell, cellIndex) => ( 32 |
    33 | ))} 34 | 35 | {SubComponent && ( 36 |
    {SubComponent(row)}
    37 | )} 38 | 39 | ) 40 | } 41 | 42 | Tr.whyDidYouRender = true 43 | 44 | Tr.propTypes = { 45 | row: PropTypes.object.isRequired, 46 | SubComponent: PropTypes.func, 47 | keyField: PropTypes.string.isRequired, 48 | style: PropTypes.object.isRequired, 49 | totalWidth: PropTypes.number.isRequired, 50 | isTrDisable: PropTypes.func 51 | } 52 | 53 | export default React.memo(Tr) 54 | -------------------------------------------------------------------------------- /table_x/hoc/diy_table_x/components/modal_list.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import SVGRemove from '../../../../svg/remove.svg' 4 | 5 | const ModalList = ({ cols, onColsRemove }) => { 6 | const onRemove = (key, e) => { 7 | e.stopPropagation() 8 | onColsRemove(key) 9 | } 10 | 11 | return ( 12 |
      13 | {cols.map(item => { 14 | const { diyItemText, Header, key, diyEnable } = item 15 | const text = diyItemText || Header 16 | return ( 17 |
    • 18 | {text} 19 | {diyEnable && ( 20 | 24 | )} 25 |
    • 26 | ) 27 | })} 28 |
    29 | ) 30 | } 31 | 32 | ModalList.propTypes = { 33 | cols: PropTypes.array.isRequired, 34 | onColsRemove: PropTypes.func.isRequired 35 | } 36 | 37 | export default ModalList 38 | -------------------------------------------------------------------------------- /table_x/hoc/edit_table_x.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classNames from 'classnames' 3 | import TableX from '../base' 4 | 5 | const editTableXHOC = Component => { 6 | const EditTable = ({ className, ...rest }) => ( 7 | 11 | ) 12 | 13 | EditTable.propTypes = { 14 | ...TableX.propTypes 15 | } 16 | 17 | return EditTable 18 | } 19 | 20 | export default editTableXHOC 21 | -------------------------------------------------------------------------------- /table_x/hoc/fixed_columns_table_x.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import TableX from '../base' 3 | import _ from 'lodash' 4 | 5 | function fixedColumnsTableXHOC(Component) { 6 | const FixedColumnTableX = ({ columns, ...rest }) => { 7 | return 8 | } 9 | 10 | FixedColumnTableX.propTypes = { 11 | ...TableX.propTypes, 12 | /** 需要固定的 column 有 fixed 字段 */ 13 | columns: props => { 14 | const { columns } = props 15 | 16 | _.each(columns, column => { 17 | if (column.fixed) { 18 | if (column.fixed !== 'left' && column.fixed !== 'right') { 19 | console.error('column fixed need to be left or right', column) 20 | } 21 | } 22 | }) 23 | } 24 | } 25 | 26 | return FixedColumnTableX 27 | } 28 | 29 | export default fixedColumnsTableXHOC 30 | -------------------------------------------------------------------------------- /table_x/hoc/sub_table_x.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classNames from 'classnames' 3 | import PropTypes from 'prop-types' 4 | import TableX from '../base' 5 | import { TABLE_X, TABLE_X_SUB_TABLE_ID } from '../util' 6 | 7 | const subTableXHOC = Component => { 8 | const SubTable = ({ subTableIndent, columns, className, ...rest }) => { 9 | const _columns = React.useMemo( 10 | () => 11 | [ 12 | { 13 | id: TABLE_X_SUB_TABLE_ID, 14 | width: subTableIndent, 15 | maxWidth: subTableIndent, 16 | Header: '' 17 | } 18 | ].concat(columns), 19 | [columns, subTableIndent] 20 | ) 21 | 22 | return ( 23 | 28 | ) 29 | } 30 | 31 | SubTable.propTypes = { 32 | ...TableX.propTypes, 33 | /** 默认功能区的宽度 */ 34 | subTableIndent: PropTypes.number 35 | } 36 | 37 | SubTable.defaultProps = { 38 | subTableIndent: TABLE_X.WIDTH_FUN 39 | } 40 | 41 | return SubTable 42 | } 43 | 44 | export default subTableXHOC 45 | -------------------------------------------------------------------------------- /table_x/index.js: -------------------------------------------------------------------------------- 1 | import TableX from './base' 2 | import TableXVirtualized from './base/virtualized' 3 | import selectTableXHOC from './hoc/select_table_x' 4 | import expandTableXHOC from './hoc/expand_table_x' 5 | import fixedColumnsTableXHOC from './hoc/fixed_columns_table_x' 6 | import sortableTableXHOC from './hoc/sortable_table_x' 7 | import subTableXHOC from './hoc/sub_table_x' 8 | import editTableXHOC from './hoc/edit_table_x' 9 | import diyTableXHOC from './hoc/diy_table_x' 10 | 11 | import { 12 | TABLE_X, 13 | BatchActionBar, 14 | OperationHeader, 15 | OperationDelete, 16 | OperationDetail, 17 | OperationCell, 18 | OperationRowEdit, 19 | EditButton, 20 | EditOperation, 21 | SortHeader 22 | } from './util' 23 | 24 | const TableXUtil = { 25 | TABLE_X, 26 | 27 | BatchActionBar, 28 | SortHeader, 29 | 30 | OperationHeader, 31 | OperationDelete, 32 | OperationDetail, 33 | OperationCell, 34 | OperationRowEdit, 35 | 36 | EditButton, 37 | EditOperation 38 | } 39 | 40 | export { 41 | TableXUtil, 42 | TableX, 43 | TableXVirtualized, 44 | selectTableXHOC, 45 | expandTableXHOC, 46 | fixedColumnsTableXHOC, 47 | subTableXHOC, 48 | editTableXHOC, 49 | diyTableXHOC, 50 | sortableTableXHOC 51 | } 52 | -------------------------------------------------------------------------------- /table_x/util/sort_header.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import PropTypes from 'prop-types' 3 | import _ from 'lodash' 4 | import React from 'react' 5 | 6 | const SortHeader = ({ type, className, onClick, onChange, ...rest }) => { 7 | const handleClick = e => { 8 | onClick(e) 9 | 10 | if (!type) { 11 | onChange('asc') 12 | } else if (type === 'asc') { 13 | onChange('desc') 14 | } else if (type === 'desc') { 15 | onChange(null) 16 | } 17 | } 18 | 19 | return ( 20 | 32 | ) 33 | } 34 | 35 | SortHeader.propTypes = { 36 | type: PropTypes.oneOf(['asc', 'desc']), 37 | /** 之前很多用了 onClick */ 38 | onClick: PropTypes.func, 39 | /** 建议用onChange,这样不用管理状态 */ 40 | onChange: PropTypes.func, 41 | className: PropTypes.string 42 | } 43 | 44 | SortHeader.defaultProps = { 45 | onClick: _.noop, 46 | onChange: _.noop 47 | } 48 | 49 | export default SortHeader 50 | -------------------------------------------------------------------------------- /table_x/variables.less: -------------------------------------------------------------------------------- 1 | .gm-table-x-edit-table-common-input { 2 | width: 100%; 3 | outline: none; 4 | border-width: 1px; 5 | border-style: solid; 6 | padding-left: 8px; 7 | padding-right: 8px; 8 | box-sizing: border-box; 9 | height: 32px; 10 | line-height: 32px; 11 | border-color: #d4d7e9; 12 | border-radius: 2px; 13 | 14 | &:hover { 15 | border-color: @brand-primary; 16 | box-shadow: 0 0 0 1px @brand-primary; 17 | } 18 | 19 | &:focus { 20 | border-color: @brand-primary; 21 | box-shadow: 0 0 0 1px @brand-primary; 22 | } 23 | 24 | &.gm-popover-active { 25 | border-color: @brand-primary; 26 | box-shadow: 0 0 0 1px @brand-primary; 27 | } 28 | } 29 | --------------------------------------------------------------------------------