├── .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 | [](https://www.npmjs.com/package/react-gm) [](https://github.com/{owner}/{repo}/actions)
2 |
3 | [](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 |
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 |
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 |
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 |
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 |
20 | )
21 | }
22 |
23 | Limit.propTypes = {
24 | value: PropTypes.any.isRequired,
25 | onChange: PropTypes.func.isRequired
26 | }
27 |
28 | const Left = ({ data, onChange, showCount }) => {
29 | const handleChangeLimit = limit => {
30 | // 回到第一页
31 | onChange({
32 | offset: 0,
33 | limit
34 | })
35 | }
36 |
37 | return (
38 |
39 | {showCount && 共{data.count}条记录, }
40 | 每页
41 |
42 | 条
43 |
44 | )
45 | }
46 |
47 | Left.propTypes = {
48 | data: PropTypes.object,
49 | onChange: PropTypes.func.isRequired,
50 | showCount: PropTypes.bool
51 | }
52 |
53 | export default Left
54 |
--------------------------------------------------------------------------------
/src/component/pagination/pagination.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import PaginationBase from './base'
4 |
5 | const Pagination = ({ data, toPage, nextDisabled, ...rest }) => {
6 | if (data.count !== undefined && data.count !== null) {
7 | return (
8 | {
12 | toPage(data)
13 | }}
14 | showCount
15 | />
16 | )
17 | } else {
18 | let count = data.offset + data.limit * 2
19 | if (nextDisabled) {
20 | count = data.offset + data.limit
21 | }
22 |
23 | return (
24 | {
28 | toPage(data)
29 | }}
30 | />
31 | )
32 | }
33 | }
34 |
35 | Pagination.displayName = 'Pagination'
36 | Pagination.propTypes = {
37 | data: PropTypes.shape({
38 | count: PropTypes.number,
39 | offset: PropTypes.number.isRequired,
40 | limit: PropTypes.number.isRequired
41 | }),
42 | /**
43 | * 参数 {offset, limit}, page。page 是页码。
44 | * 直接用此数据请求后台即可
45 | */
46 | toPage: PropTypes.func.isRequired,
47 | /** data without count 才有效 */
48 | nextDisabled: PropTypes.bool,
49 | className: PropTypes.string,
50 | style: PropTypes.object
51 | }
52 |
53 | export default Pagination
54 |
--------------------------------------------------------------------------------
/src/component/pagination/pagination_v2.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import PaginationBase from './base'
4 |
5 | const PaginationV2 = props => {
6 | return
7 | }
8 |
9 | PaginationV2.displayName = 'PaginationV2'
10 | PaginationV2.propTypes = {
11 | /** 非传统意义上的 分页信息。 仅此组件需要的数据而已。count 仅当前有多少条数据,非传统意义上的一共多少条数据,注意是当前。 */
12 | data: PropTypes.shape({
13 | count: PropTypes.number.isRequired,
14 | offset: PropTypes.number.isRequired,
15 | limit: PropTypes.number.isRequired
16 | }),
17 | /** 提供 {offset, limit} */
18 | onChange: PropTypes.func.isRequired,
19 | /** 此 count 非 data.count。此只是用来控制不显示总数 */
20 | showCount: PropTypes.bool,
21 | className: PropTypes.string,
22 | style: PropTypes.object,
23 | /** 私有 */
24 | _peekInfo: PropTypes.shape({
25 | more: PropTypes.bool,
26 | peek: PropTypes.number
27 | })
28 | }
29 |
30 | export default PaginationV2
31 |
--------------------------------------------------------------------------------
/src/component/pagination/style.less:
--------------------------------------------------------------------------------
1 | .gm-pagination {
2 | .gm-pagination-page {
3 | margin-left: 20px;
4 |
5 | .gm-pagination-page-item {
6 | margin: 0 5px;
7 | border: 1px solid @gm-border-color;
8 | border-radius: @gm-border-radius;
9 | height: 30px;
10 | line-height: 30px;
11 | min-width: 30px;
12 | text-align: center;
13 | cursor: pointer;
14 |
15 | &:hover {
16 | border: 1px solid @brand-primary;
17 | color: @brand-primary;
18 | }
19 |
20 | &.active {
21 | background-color: @brand-primary;
22 | border: 1px solid @brand-primary;
23 | color: white;
24 | }
25 |
26 | &.disabled {
27 | cursor: not-allowed;
28 | background-color: #f0f1f3;
29 | border: 1px solid @gm-border-color;
30 | color: @gm-color-first;
31 | }
32 | }
33 |
34 | .gm-pagination-page-text {
35 | color: @gm-color-third;
36 | }
37 | }
38 |
39 | .gm-pagination-right {
40 | margin-left: 10px;
41 |
42 | .gm-pagination-right-total-page {
43 | height: 30px;
44 | line-height: 30px;
45 | text-align: center;
46 | padding: 0 5px;
47 | background-color: #f0f1f3;
48 | border: 1px solid @gm-border-color;
49 | border-left: none;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/component/pagination/util.js:
--------------------------------------------------------------------------------
1 | function getIndex(data) {
2 | return data.offset / data.limit + 1
3 | }
4 |
5 | export { getIndex }
6 |
--------------------------------------------------------------------------------
/src/component/popup/index.js:
--------------------------------------------------------------------------------
1 | import Popup from './popup'
2 | import PopupContentConfirm from './popup_content_confirm'
3 |
4 | export { Popup, PopupContentConfirm }
5 |
--------------------------------------------------------------------------------
/src/component/price/stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import _ from 'lodash'
4 | import Price from './index'
5 |
6 | const list = [
7 | 0,
8 | 10839,
9 | 2345454545,
10 | 1000,
11 | 12310,
12 | 10000000,
13 | -10,
14 | -226,
15 | -1000,
16 | -1000002323
17 | ]
18 |
19 | storiesOf('Price', module).add('default', () => (
20 |
21 | {_.map(list, v => (
22 |
25 | ))}
26 |
{' '}
27 |
28 |
33 |
34 | ))
35 |
--------------------------------------------------------------------------------
/src/component/progress_circle/stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import ProgressCircle from './index'
4 | import { observable } from 'mobx'
5 |
6 | const store = observable({
7 | percentage: 0,
8 | setPercentage(percentage) {
9 | this.percentage = percentage
10 | }
11 | })
12 |
13 | setTimeout(() => {
14 | store.setPercentage(80)
15 | }, 1000)
16 |
17 | storiesOf('ProgressCircle', module).add('default', () => (
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
53 |
54 | ))
55 |
--------------------------------------------------------------------------------
/src/component/progress_circle/style.less:
--------------------------------------------------------------------------------
1 | .gm-progress-circle-success {
2 | stroke: @brand-primary;
3 | }
4 |
5 | .gm-progress-circle-exception {
6 | stroke: @brand-danger;
7 | }
8 |
9 | .gm-progress-circle-innerText-right {
10 | font-size: 12px;
11 | margin-left: 5px;
12 | }
13 |
14 | .gm-progress-circle-innerText-left {
15 | font-size: 12px;
16 | margin-right: 5px;
17 | }
18 |
--------------------------------------------------------------------------------
/src/component/radio/index.js:
--------------------------------------------------------------------------------
1 | import Radio from './radio'
2 | import RadioGroup from './radio_group'
3 |
4 | export { Radio, RadioGroup }
5 |
--------------------------------------------------------------------------------
/src/component/radio/radio_group.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classNames from 'classnames'
4 | import _ from 'lodash'
5 |
6 | class RadioGroup extends React.Component {
7 | render() {
8 | const {
9 | onChange,
10 | value,
11 | inline,
12 | className,
13 | children,
14 | name,
15 | ...rest
16 | } = this.props
17 |
18 | return (
19 |
20 | {_.map(React.Children.toArray(children), (child, i) => {
21 | return React.cloneElement(child, {
22 | key: i,
23 | index: i,
24 | checked: child.props.value === value,
25 | inline,
26 | onChange: () => {
27 | onChange(child.props.value)
28 | },
29 | name
30 | })
31 | })}
32 |
33 | )
34 | }
35 | }
36 |
37 | RadioGroup.propTypes = {
38 | name: PropTypes.string.isRequired,
39 | value: PropTypes.any,
40 | onChange: PropTypes.func,
41 | inline: PropTypes.bool,
42 | children: PropTypes.any,
43 | className: PropTypes.string,
44 | style: PropTypes.object
45 | }
46 |
47 | RadioGroup.defaultProps = {
48 | onChange: _.noop
49 | }
50 |
51 | export default RadioGroup
52 |
--------------------------------------------------------------------------------
/src/component/select/index.js:
--------------------------------------------------------------------------------
1 | import Select from './select'
2 | import Option from './option'
3 |
4 | export { Select, Option }
5 |
--------------------------------------------------------------------------------
/src/component/select/option.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | const Option = () => {
5 | useEffect(() => {
6 | console.warn('Deprecated. Use Select data instead.')
7 | }, [])
8 |
9 | return null
10 | }
11 |
12 | Option.displayName = 'Option'
13 |
14 | Option.propTypes = {
15 | value: PropTypes.any,
16 | disabled: PropTypes.bool,
17 | children: PropTypes.any,
18 | className: PropTypes.string,
19 | style: PropTypes.object
20 | }
21 |
22 | export default Option
23 |
--------------------------------------------------------------------------------
/src/component/select/style.less:
--------------------------------------------------------------------------------
1 | .gm-select {
2 | display: inline-block;
3 | vertical-align: middle;
4 | }
5 |
--------------------------------------------------------------------------------
/src/component/selection/selection.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import Selection from './'
4 |
5 | storiesOf('内部|Selection', module)
6 | .add('default', () => (
7 | console.log(selected)}
9 | placeholder='请选择'
10 | />
11 | ))
12 | .add('disabled', () => (
13 | console.log(selected)}
16 | placeholder='请选择'
17 | />
18 | ))
19 | .add('自定义选中项', () => (
20 | console.log(selected)}
23 | renderSelected={item => item.text + 'lalala'}
24 | />
25 | ))
26 | .add('clean', () => (
27 | console.log(selected)}
31 | placeholder='请选择'
32 | />
33 | ))
34 | .add('disabledClose', () => (
35 | console.log(selected)}
39 | placeholder='请选择'
40 | />
41 | ))
42 |
--------------------------------------------------------------------------------
/src/component/selection/style.less:
--------------------------------------------------------------------------------
1 | .gm-selection {
2 | position: relative;
3 | vertical-align: middle;
4 | height: 30px;
5 |
6 | .gm-selection-selected {
7 | display: block;
8 | padding-right: 24px;
9 | cursor: pointer;
10 | line-height: 18px;
11 | }
12 |
13 | .gm-selection-icon {
14 | position: absolute;
15 | display: block;
16 | line-height: 1;
17 | top: 9px;
18 | right: 6px;
19 | color: @gm-color-fourth;
20 | cursor: pointer;
21 | }
22 |
23 | .gm-selection-close-icon {
24 | display: none;
25 | right: 6px;
26 | }
27 |
28 | .gm-selection-down-up {
29 | right: 6px;
30 | }
31 |
32 | &:hover {
33 | .gm-selection-close-icon {
34 | display: block;
35 | }
36 |
37 | .gm-selection-fun-icon {
38 | display: none;
39 | }
40 | }
41 |
42 | &.disabled {
43 | cursor: not-allowed;
44 |
45 | .gm-selection-selected {
46 | cursor: not-allowed;
47 | border: 1px solid @gm-border-color;
48 | }
49 |
50 | .gm-selection-close-icon {
51 | cursor: not-allowed;
52 | }
53 | }
54 |
55 | &.gm-selection-disabled-close {
56 | .gm-selection-selected {
57 | padding-right: 20px;
58 | }
59 | }
60 |
61 | &.gm-selection-disabled-clean {
62 | .gm-selection-selected {
63 | padding-right: 20px;
64 | border: 1px solid transparent;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/component/sheet/index.js:
--------------------------------------------------------------------------------
1 | import Sheet from './sheet'
2 | import SheetColumn from './sheet_column'
3 | import SheetAction from './sheet_action'
4 | import SheetSelect from './sheet_select'
5 | import SheetBatchAction from './sheet_batch_action'
6 |
7 | export { Sheet, SheetColumn, SheetAction, SheetSelect, SheetBatchAction }
8 |
--------------------------------------------------------------------------------
/src/component/sheet/sheet_action.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | class SheetAction extends React.Component {
5 | render() {
6 | return {this.props.children}
7 | }
8 | }
9 |
10 | SheetAction.propTypes = {
11 | children: PropTypes.any
12 | }
13 |
14 | SheetAction.displayName = 'SheetAction'
15 |
16 | export default SheetAction
17 |
--------------------------------------------------------------------------------
/src/component/sheet/sheet_batch_action.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | class SheetBatchAction extends React.Component {
5 | render() {
6 | return {this.props.children}
7 | }
8 | }
9 |
10 | SheetBatchAction.propTypes = {
11 | children: PropTypes.any
12 | }
13 |
14 | SheetBatchAction.displayName = 'SheetBatchAction'
15 |
16 | export default SheetBatchAction
17 |
--------------------------------------------------------------------------------
/src/component/sheet/sheet_column.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | class SheetColumn extends React.Component {
5 | render() {
6 | return null
7 | }
8 | }
9 |
10 | SheetColumn.displayName = 'SheetColumn'
11 | SheetColumn.propTypes = {
12 | field: PropTypes.string.isRequired,
13 | name: PropTypes.oneOfType([
14 | PropTypes.string.isRequired,
15 | PropTypes.element.isRequired
16 | ]),
17 | render: PropTypes.func,
18 | placeholder: PropTypes.any
19 | }
20 |
21 | export default SheetColumn
22 |
--------------------------------------------------------------------------------
/src/component/sheet/sheet_select.js:
--------------------------------------------------------------------------------
1 | import { getLocale } from '../../locales'
2 | import React from 'react'
3 | import PropTypes from 'prop-types'
4 | import _ from 'lodash'
5 |
6 | class SheetSelect extends React.Component {
7 | render() {
8 | return {this.props.children}
9 | }
10 | }
11 |
12 | SheetSelect.displayName = 'SheetSelect'
13 | SheetSelect.propTypes = {
14 | onSelect: PropTypes.func.isRequired,
15 | onSelectAll: PropTypes.func,
16 | onChange: PropTypes.func,
17 | isDisabled: PropTypes.func,
18 | isRadio: PropTypes.bool,
19 | hasSelectTip: PropTypes.bool,
20 | selectAllTip: PropTypes.node,
21 | children: PropTypes.any
22 | }
23 | SheetSelect.defaultProps = {
24 | onSelect: _.noop,
25 | isDisabled: () => false,
26 | isRadio: false,
27 | hasSelectTip: false,
28 | selectAllTip: getLocale('已选中所有')
29 | }
30 |
31 | export default SheetSelect
32 |
--------------------------------------------------------------------------------
/src/component/steps/steps.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import Steps from './index'
4 |
5 | storiesOf('Steps', module).add('default', () => (
6 |
15 | ))
16 |
--------------------------------------------------------------------------------
/src/component/steps/style.less:
--------------------------------------------------------------------------------
1 | @gm-icon-diameter: 18px;
2 |
3 | .gm-steps {
4 | .gm-steps-step {
5 | &:first-child {
6 | margin-top: 0 !important;
7 | }
8 |
9 | // 线条
10 | .gm-steps-step-tag {
11 | width: 1px;
12 | height: 25px;
13 | background: @brand-primary;
14 | }
15 |
16 | &:last-child .gm-steps-step-tag {
17 | display: none;
18 | }
19 |
20 | .gm-steps-step-icon {
21 | border: 1px @brand-primary solid;
22 | border-radius: 50%;
23 | line-height: @gm-icon-diameter;
24 | text-align: center;
25 | width: @gm-icon-diameter;
26 | height: @gm-icon-diameter;
27 | color: @brand-primary;
28 | }
29 |
30 | .gm-steps-step-title {
31 | height: @gm-icon-diameter + 2; // 加上icon边框宽度
32 | line-height: @gm-icon-diameter + 2; // 加上icon边框宽度
33 | }
34 |
35 | .gm-steps-step-description {
36 | color: @gm-color-fourth;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/component/storage/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import PropTypes from 'prop-types'
3 | import _ from 'lodash'
4 |
5 | const prefix = '_react-gm_'
6 | const { localStorage } = window
7 |
8 | const StorageStatics = {
9 | set(key, value) {
10 | localStorage.setItem(prefix + key, JSON.stringify(value))
11 | },
12 | get(key) {
13 | const v = localStorage.getItem(prefix + key)
14 | return v ? JSON.parse(v) : v
15 | },
16 | remove(key) {
17 | localStorage.removeItem(prefix + key)
18 | },
19 | clear() {
20 | localStorage.clear()
21 | },
22 | getAll() {
23 | const result = {}
24 | _.each(_.range(localStorage.length), i => {
25 | let key = localStorage.key(i)
26 | if (key.startsWith(prefix)) {
27 | key = key.slice(prefix.length)
28 | result[key] = StorageStatics.get(key)
29 | }
30 | })
31 | return _.keys(result) ? result : null
32 | }
33 | }
34 |
35 | const Storage = ({ name, value }) => {
36 | useEffect(() => {
37 | StorageStatics.set(name, value)
38 | }, [value])
39 |
40 | return null
41 | }
42 |
43 | Object.assign(Storage, StorageStatics)
44 |
45 | Storage.propTypes = {
46 | name: PropTypes.string.isRequired,
47 | value: PropTypes.oneOfType([
48 | PropTypes.string,
49 | PropTypes.object,
50 | PropTypes.array
51 | ])
52 | }
53 |
54 | export default Storage
55 |
--------------------------------------------------------------------------------
/src/component/storage/stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { observable } from 'mobx'
4 | import Storage from './index'
5 |
6 | const store = observable({
7 | data: 'ad',
8 | setData(data) {
9 | this.data = data
10 | }
11 | })
12 |
13 | storiesOf('Storage', module).add(
14 | 'default',
15 | () => (
16 |
17 | 实时存储
18 | 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 |
9 |
--------------------------------------------------------------------------------
/svg/calendar-year.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/svg/calendar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/svg/check-detail.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
--------------------------------------------------------------------------------
/svg/close-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/svg/closeup.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/svg/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/svg/down-small.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/svg/down.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/svg/edit-box.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/svg/edit-pen.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/svg/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svg/expand.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
11 |
--------------------------------------------------------------------------------
/svg/next.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
41 |
--------------------------------------------------------------------------------
/svg/ok.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svg/pen.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
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 |
--------------------------------------------------------------------------------