beyond-rails 0.0.227 → 0.0.232

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4240bb4020f2fa8d7a190f8026ba1bc9434e0a20ccc545156ff5935ad174f76c
4
- data.tar.gz: b0eef0c93430d3955695451c4db43fb350dfbd02afe9bf16e1a49d5df3f543e0
3
+ metadata.gz: 2b9562fcd46c8ebb8eb393ebbde56ddc3ace49fc91dc072c864586b7efa9c7f7
4
+ data.tar.gz: 5e2ff6d2ad3c8f5df2eb4a3ee3ec81dd2edcd50149a3e957d8dba12ad4ac6077
5
5
  SHA512:
6
- metadata.gz: b050adf27c9cf90bae213bd72144f227b2ff831c5c2b768380ee44473fa31f1b885032c66ff66c31874a78025a07f9f00238ced01ce861d68d644a2bd5f265a6
7
- data.tar.gz: e763f9218b0ea16809f0ad13f6027b06758e26604789f85b44e54341a3ae88ff0027abc36b6a3edfb5f8d29c90794cd959bc809e820a5f4f907e8a3b1eab0f91
6
+ metadata.gz: 2d856bb1e158d85d71618b26d0cde2d5bab43a9cdad0cc27f4175b400bcb19ab47274609b9b5b6e6e22c7664db7aeb035b6b7db9b91ffb84e915ddfd761d1838
7
+ data.tar.gz: 4205d83e358f13508a52f1ed92b41aef10bf684fcc9f86ce3bb0543dc4393ee838c9dfe6ba679dc1ec5f269768a6f9f6d352d7e523ba9dd09d14d449df1b8358
@@ -51,15 +51,28 @@ export default class Dropdown {
51
51
  this.addEvents()
52
52
  }
53
53
 
54
- hideMenu() {
54
+ restoreMenuAttrs() {
55
+ const { menu, place, align } = this
56
+ if (place) {
57
+ menu.dataset.place = place
58
+ }
59
+ if (align) {
60
+ menu.dataset.align = align
61
+ }
62
+ }
63
+
64
+ hideMenu(immediate = false) {
55
65
  const { menu } = this
56
66
  menu.style.transform = 'scale(.8)'
57
67
  menu.style.opacity = 0
58
- setTimeout(() => menu.remove(), 300)
59
68
 
60
- // recover
61
- menu.dataset.place = this.place
62
- menu.dataset.align = this.align
69
+ if (immediate) {
70
+ menu.remove()
71
+ }
72
+ else {
73
+ setTimeout(() => menu.remove(), 300)
74
+ }
75
+ this.restoreMenuAttrs()
63
76
  this.isMenuVisible = false
64
77
  }
65
78
 
@@ -145,4 +158,13 @@ export default class Dropdown {
145
158
  this.adjustMenuPos()
146
159
  }, 300))
147
160
  }
161
+
162
+ destroy() {
163
+ // prevent next re-bind error
164
+ const { menu } = this
165
+ if (menu) {
166
+ this.hideMenu(true)
167
+ document.body.appendChild(menu)
168
+ }
169
+ }
148
170
  }
@@ -20,8 +20,11 @@ export default class SearchDropdown {
20
20
  this.options.itemClick = options.itemClick || itemClick
21
21
  this.options.change = options.change || noop
22
22
  this.options.wait = options.wait || 50
23
- this.place = 'bottom'
24
- this.align = 'left'
23
+ this.place = options.place || 'bottom'
24
+ this.align = options.align || 'left'
25
+ this.offset = options.offset || 14
26
+ this.offsetTop = options.offsetTop || 0
27
+ this.offsetLeft = options.offsetLeft || 0
25
28
  this.isMenuVisible = false
26
29
  this.lastKeyword = null
27
30
  this.selectedIndex = 0
@@ -53,7 +56,16 @@ export default class SearchDropdown {
53
56
  }
54
57
 
55
58
  appendMenu() {
59
+
56
60
  const menu = document.createElement('div')
61
+ const { dataset } = menu
62
+
63
+ dataset.place = this.place
64
+ dataset.align = this.align
65
+ dataset.offset = this.offset
66
+ dataset.offsetTop = this.offsetTop
67
+ dataset.offsetLeft = this.offsetLeft
68
+
57
69
  menu.className = 'search-dropdown dropdown-menu'
58
70
 
59
71
  const inputWrap = document.createElement('div')
@@ -100,15 +112,19 @@ export default class SearchDropdown {
100
112
  showMenu() {
101
113
  const { input, menu } = this
102
114
  this.getData(input.value)
115
+
103
116
  menu.style.display = 'block'
104
117
  menu.style.opacity = 0
105
118
  menu.style.transform = 'scale(.8)'
106
119
  document.body.appendChild(menu)
107
- this.adjustMenuPos()
108
- menu.style.transform = 'scale(1)'
109
- menu.style.opacity = 1
110
- this.isMenuVisible = true
111
- this.input.focus()
120
+
121
+ setTimeout(() => {
122
+ this.adjustMenuPos()
123
+ menu.style.transform = 'scale(1)'
124
+ menu.style.opacity = 1
125
+ this.isMenuVisible = true
126
+ this.input.focus()
127
+ }, 0)
112
128
  }
113
129
 
114
130
  toggleMenu() {
@@ -116,22 +132,18 @@ export default class SearchDropdown {
116
132
  }
117
133
 
118
134
  adjustMenuPos() {
119
- const { menu, dom } = this
120
- const { dataset } = menu
121
- const offsetLeft = ('offsetLeft' in dataset) ? parseInt(dataset.offsetLeft, 10) : 0
122
- const offsetTop = ('offsetTop' in dataset) ? parseInt(dataset.offsetTop, 10) : 0
123
-
135
+ const { menu, dom, offset, offsetLeft, offsetTop } = this
124
136
  const { pos, place, align } = getFloatedTargetPos({
125
137
  src: dom,
126
138
  target: menu,
127
139
  place: this.place,
128
140
  align: this.align,
129
- offset: parseInt(dom.dataset.offset, 10) || 14,
141
+ offset,
130
142
  offsetLeft,
131
143
  offsetTop
132
144
  })
133
- dataset.place = place
134
- dataset.align = align
145
+ menu.dataset.place = place
146
+ menu.dataset.align = align
135
147
  menu.style.left = toPixel(pos.left)
136
148
  menu.style.top = toPixel(pos.top)
137
149
  }
@@ -0,0 +1,144 @@
1
+ import raf from '../utils/raf'
2
+ import supportDom from '../decorators/supportDom'
3
+ import getKey from '../utils/getKey'
4
+
5
+ @supportDom
6
+ export default class TagInput {
7
+
8
+ constructor(dom, options = {}) {
9
+ this.dom = dom
10
+ this.defaultInputWidth = 128
11
+ this.validate = options.validate || (() => ({ isTag: true }))
12
+ this.change = options.change || (() => {})
13
+ this.isComposing = false
14
+ this.raf = raf
15
+ this.tags = []
16
+ this.init()
17
+ }
18
+
19
+ init() {
20
+ this.setup()
21
+ this.addEvents()
22
+ }
23
+
24
+ setup() {
25
+ const input = document.createElement('input')
26
+ input.type = 'text'
27
+ input.style.width = this.defaultInputWidth + 'px'
28
+ this.input = input
29
+ this.canvas = document.createElement('canvas')
30
+ this.dom.append(input)
31
+ }
32
+
33
+ getTextWidth(text, font) {
34
+ const context = this.canvas.getContext('2d')
35
+ context.font = font
36
+ const metrics = context.measureText(text)
37
+ return metrics.width
38
+ }
39
+
40
+ getNextInputWidth(textWidth) {
41
+ const { defaultInputWidth } = this
42
+ // spaces before text and after text
43
+ const delta = 5
44
+ const nextWidth = textWidth + delta
45
+ if (nextWidth < defaultInputWidth) {
46
+ return defaultInputWidth
47
+ }
48
+ return nextWidth
49
+ }
50
+
51
+ shake() {
52
+ this.dom.classList.add('shake')
53
+ setTimeout(() => {
54
+ this.dom.classList.remove('shake')
55
+ }, 500)
56
+ }
57
+
58
+ async addTagIfNeeded(value) {
59
+ const { input } = this
60
+ const inputValue = input.value
61
+ const res = await this.validate(inputValue)
62
+ if (! res.isTag) {
63
+ return this.shake()
64
+ }
65
+ const classname = res.classname ? ` ${res.classname}` : ''
66
+ const tag = document.createElement('div')
67
+
68
+ tag.className = 'tag' + classname
69
+ tag.textContent = inputValue
70
+
71
+ const btn = document.createElement('button')
72
+ btn.type = 'button'
73
+
74
+ // https://wesbos.com/times-html-entity-close-button
75
+ btn.textContent = '×'
76
+ const handleBtnClick = () => {
77
+ this.tags = this.tags.filter(row => row.elem !== tag)
78
+ btn.removeEventListener('click', handleBtnClick)
79
+ tag.remove()
80
+ this.change(this.tags.slice())
81
+ }
82
+ btn.addEventListener('click', handleBtnClick)
83
+ tag.appendChild(btn)
84
+
85
+ this.tags.push({ elem: tag, remove: handleBtnClick, res })
86
+ this.dom.insertBefore(tag, input)
87
+ input.value = ''
88
+
89
+ this.change(this.tags.slice())
90
+ }
91
+
92
+ removeTagIfNeeded() {
93
+ const lastTag = this.tags[this.tags.length - 1]
94
+ if ((this.input.value === '') && lastTag) {
95
+ lastTag.remove()
96
+ }
97
+ }
98
+
99
+ addEvents() {
100
+ const { input } = this
101
+ const font = window.getComputedStyle(input)
102
+ .getPropertyValue('font')
103
+
104
+ this.addEvent(this.dom, 'click', event => {
105
+ if (event.target === this.dom) {
106
+ this.input.focus()
107
+ }
108
+ })
109
+
110
+ this.addEvent(input, 'compositionstart', event => {
111
+ this.isComposing = true
112
+ })
113
+
114
+ this.addEvent(input, 'compositionend', event => {
115
+ this.isComposing = false
116
+ })
117
+
118
+ let lastValue = ''
119
+
120
+ this.addEvent(input, 'keydown', async event => {
121
+ const key = getKey(event)
122
+ if ((key === 'enter') && (! this.isComposing)) {
123
+ await this.addTagIfNeeded(input.value)
124
+ }
125
+ else if ((key === 'backspace') && (lastValue === '')) {
126
+ this.removeTagIfNeeded()
127
+ }
128
+ lastValue = input.value
129
+ })
130
+
131
+ this.addEvent(input, 'input', event => {
132
+ this.raf(() => {
133
+ const textWidth = this.getTextWidth(input.value, font)
134
+ const nextWidth = this.getNextInputWidth(textWidth)
135
+ input.style.width = nextWidth + 'px'
136
+ })
137
+ })
138
+ }
139
+
140
+ destroy() {
141
+ this.tags.forEach(tag => tag.remove())
142
+ this.input.remove()
143
+ }
144
+ }
@@ -1,4 +1,4 @@
1
- import isDef from '../utils/isDef'
1
+ import raf from '../utils/raf'
2
2
  import isUndef from '../utils/isUndef'
3
3
  import { getDomPos, range, toPixel, isFunction } from '../utils'
4
4
 
@@ -6,6 +6,11 @@ export default function chartCommon(target) {
6
6
 
7
7
  return class extends target {
8
8
 
9
+ constructor(...args) {
10
+ super(...args)
11
+ this.raf = raf
12
+ }
13
+
9
14
  init() {
10
15
  this.layers = []
11
16
  if (isFunction(super.init)) {
@@ -159,13 +164,6 @@ export default function chartCommon(target) {
159
164
  return this.ctx.measureText(value).width
160
165
  }
161
166
 
162
- raf(fn) {
163
- if (isDef(window.requestAnimationFrame)) {
164
- return window.requestAnimationFrame(fn)
165
- }
166
- return fn()
167
- }
168
-
169
167
  removeAllLayers() {
170
168
  const { dom } = this
171
169
  this.layers.forEach(layer => {
@@ -20,6 +20,7 @@ import Navbar from './components/Navbar'
20
20
  import Radio from './components/Radio'
21
21
  import SearchDropdown from './components/SearchDropdown'
22
22
  import Sidebar from './components/Sidebar'
23
+ import TagInput from './components/TagInput'
23
24
  import Tabbox from './components/Tabbox'
24
25
  import Timepicker from './components/Timepicker'
25
26
  import Toast from './components/Toast'
@@ -55,6 +56,7 @@ export {
55
56
  Radio,
56
57
  SearchDropdown,
57
58
  Sidebar,
59
+ TagInput,
58
60
  Tabbox,
59
61
  Timepicker,
60
62
  Toast,
@@ -1,4 +1,5 @@
1
1
  const keyMap = {
2
+ 8: 'backspace',
2
3
  13: 'enter',
3
4
  17: 'ctrl',
4
5
  27: 'esc',
@@ -0,0 +1,3 @@
1
+ export default function isStr(value) {
2
+ return (typeof value === 'string')
3
+ }
@@ -0,0 +1,8 @@
1
+ import isDef from './isDef'
2
+
3
+ export default function raf(fn) {
4
+ if (isDef(window.requestAnimationFrame)) {
5
+ return window.requestAnimationFrame(fn)
6
+ }
7
+ return fn()
8
+ }
@@ -0,0 +1,13 @@
1
+ @keyframes shake {
2
+ 0% { transform: translate(1px, 1px) rotate(0deg); }
3
+ 10% { transform: translate(-1px, -2px) rotate(-1deg); }
4
+ 20% { transform: translate(-3px, 0px) rotate(1deg); }
5
+ 30% { transform: translate(3px, 2px) rotate(0deg); }
6
+ 40% { transform: translate(1px, -1px) rotate(1deg); }
7
+ 50% { transform: translate(-1px, 2px) rotate(-1deg); }
8
+ 60% { transform: translate(-3px, 1px) rotate(0deg); }
9
+ 70% { transform: translate(3px, 1px) rotate(-1deg); }
10
+ 80% { transform: translate(-1px, -1px) rotate(1deg); }
11
+ 90% { transform: translate(1px, 2px) rotate(0deg); }
12
+ 100% { transform: translate(1px, -2px) rotate(-1deg); }
13
+ }
@@ -5,6 +5,7 @@
5
5
  @import './vendor/_turbolink';
6
6
  @import './base/_background';
7
7
  @import './base/_typography';
8
+ @import './_animations';
8
9
  @import './_main';
9
10
  @import './layout/_border-util';
10
11
  @import './layout/_col';
@@ -44,6 +45,7 @@
44
45
  @import './components/_tabbox';
45
46
  @import './components/_table';
46
47
  @import './components/_tag';
48
+ @import './components/_tag-input';
47
49
  @import './components/_time-input';
48
50
  @import './components/_time-menu';
49
51
  @import './components/_toast';
@@ -345,6 +345,9 @@ input[type="file"] {
345
345
  > .form-control {
346
346
  flex: 1 1 0%;
347
347
  }
348
+ .invalid-feedback {
349
+ flex-basis: 100%;
350
+ }
348
351
  }
349
352
 
350
353
  .input-group-text {
@@ -1,4 +1,5 @@
1
1
  .search-dropdown.dropdown-menu {
2
+ width: 420px;
2
3
  padding: 0;
3
4
  .search-dropdown-input-wrap {
4
5
  padding: 14px;
@@ -26,8 +27,5 @@
26
27
  color: #6772e5;
27
28
  margin-right: .7em;
28
29
  }
29
- > span {
30
- max-width: 420px;
31
- }
32
30
  }
33
31
  }
@@ -0,0 +1,26 @@
1
+ .tag-input {
2
+ cursor: text;
3
+ background-color: #fff;
4
+ padding: .4em .4em 0 .4em;
5
+ min-height: 40px;
6
+ > input {
7
+ border: 0;
8
+ &:focus {
9
+ outline: none;
10
+ }
11
+ }
12
+ .tag {
13
+ padding-right: 0;
14
+ display: inline-flex;
15
+ align-items: center;
16
+ margin-right: .7em;
17
+ margin-bottom: .7em;
18
+ > button {
19
+ border: 0;
20
+ background-color: transparent;
21
+ }
22
+ }
23
+ &.shake {
24
+ animation: shake .5s;
25
+ }
26
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beyond-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.227
4
+ version: 0.0.232
5
5
  platform: ruby
6
6
  authors:
7
7
  - kmsheng
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-10-12 00:00:00.000000000 Z
12
+ date: 2020-10-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sassc
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '5.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: will_paginate
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 3.3.0
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 3.3.0
82
96
  description:
83
97
  email: kmsh3ng@gmail.com
84
98
  executables: []
@@ -130,6 +144,7 @@ files:
130
144
  - src/js/components/SearchDropdown.js
131
145
  - src/js/components/Sidebar.js
132
146
  - src/js/components/Tabbox.js
147
+ - src/js/components/TagInput.js
133
148
  - src/js/components/TimeInput.js
134
149
  - src/js/components/TimeMenu.js
135
150
  - src/js/components/Timepicker.js
@@ -180,11 +195,14 @@ files:
180
195
  - src/js/utils/index.js
181
196
  - src/js/utils/isDef.js
182
197
  - src/js/utils/isInt.js
198
+ - src/js/utils/isStr.js
183
199
  - src/js/utils/isTouchDevice.js
184
200
  - src/js/utils/isUndef.js
185
201
  - src/js/utils/msToS.js
186
202
  - src/js/utils/promisify.js
203
+ - src/js/utils/raf.js
187
204
  - src/js/utils/unbindAll.js
205
+ - src/sass/_animations.scss
188
206
  - src/sass/_beyond-sprockets.scss
189
207
  - src/sass/_beyond.scss
190
208
  - src/sass/_main.scss
@@ -225,6 +243,7 @@ files:
225
243
  - src/sass/components/_switch.scss
226
244
  - src/sass/components/_tabbox.scss
227
245
  - src/sass/components/_table.scss
246
+ - src/sass/components/_tag-input.scss
228
247
  - src/sass/components/_tag.scss
229
248
  - src/sass/components/_time-input.scss
230
249
  - src/sass/components/_time-menu.scss