beyond-rails 0.0.228 → 0.0.233

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d82d76600a18e4dddf1f90ec992290bc8a69926b5c692078f61d80bb0e68848f
4
- data.tar.gz: 6619b2c4e47a4f7c05527ef852326c83a2d6d8049d0fb1db55156d701986874e
3
+ metadata.gz: 89c9f25010a6deb7c07fd392f5ba12feeaefb1a46fe0d8b72ba48c4bc5b431d4
4
+ data.tar.gz: eb9ca399dce141a787cbc0848eabdce20062b0cda24877935b3fc91527177c21
5
5
  SHA512:
6
- metadata.gz: 1bcf523d47193022e785bf994ce5a186683211fa1afd5007cdf31699fb9d6d0ff53bdc81b1fde8edd0511c17b2bc51c657c28da4cf9d0b4576b1786f7fee5cd8
7
- data.tar.gz: 54c2534a83ffb83f4281920d1fa2d7a688beda57168282ce253bc53afb48df596121dfb04b05cf611adc26e99c6e089b09d233d4ec3d9873260b38faca752160
6
+ metadata.gz: f016a0df26bf377aa5cbeea5b6ac9696b3a20b2e5817faff4c4193263bcdb4e0c167a93197fa16a08db64e54779bf63de780c729fb4c94a88d681331c3aa660d
7
+ data.tar.gz: 4bb6585874c2bd701aec8ba3851b85c61b1deba91eaabb3ccc90e1657be7ce51f09dd7093d288d4da26be39c1226bf4a34769cbb47d7184ef6a352bd80c93ac5
@@ -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';
@@ -153,6 +153,10 @@ $color-active: #5469d4;
153
153
  border: 0;
154
154
  }
155
155
 
156
+ .full-width {
157
+ width: 100% !important;
158
+ }
159
+
156
160
  hr {
157
161
  margin-top: 20px;
158
162
  margin-bottom: 20px;
@@ -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.228
4
+ version: 0.0.233
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-28 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