beyond-rails 0.0.229 → 0.0.230

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: 6eb3a6d0140c228f4cf167707a98fcc338f005de8f44fdfc160f8f0b31cc95fe
4
- data.tar.gz: 7bf45b85d53d4bfbb6856687d31e68fd23f53addaceb8e8c7783bc0847c60f93
3
+ metadata.gz: cf80575d0a2ac63e76f75b053115cd6c5518382878d406745c4f959d602d2767
4
+ data.tar.gz: b4c4372056bc1e9d5deddafbf62cadb8ab5ac8f53e3761a36f876b8b4db3897d
5
5
  SHA512:
6
- metadata.gz: 67f40335950e4e6874d3bd6e7869610d67f9fffffe7708647703036522403f754c733f74bb6e20824255ee408bc40224a1784d56916bcfcea1b9213faaec5e02
7
- data.tar.gz: dbd66629f50809e95d2cb86308ce40601bdccfb0681eb5167982c94a76e10a3bb217b12caa4f5484784a973ccb5dc844f25edb9f3e11042ca7c53f1d2a61884e
6
+ metadata.gz: e6c4b45f205f287d815e16e2b1b9065463a730f66c6e4eb62189165e37b29eede35006033568840aba125af4f0ef79740cab5458095aae0ac7a49935b24d07e8
7
+ data.tar.gz: ff1f358c7be11d00acfe9756e163be5391188f8d2b7f6581f95aeb1bcc2dc1552be875e63862960be5e3bd97dc225ee4e0535033b908cdef3aab7588defce173
@@ -0,0 +1,145 @@
1
+ import raf from '../utils/raf'
2
+ import isStr from '../utils/isStr'
3
+ import supportDom from '../decorators/supportDom'
4
+ import getKey from '../utils/getKey'
5
+
6
+ @supportDom
7
+ export default class TagInput {
8
+
9
+ constructor(dom, options = {}) {
10
+ this.dom = dom
11
+ this.defaultInputWidth = 128
12
+ this.validate = options.validate || (() => ({ isTag: true }))
13
+ this.change = options.change || (() => {})
14
+ this.isComposing = false
15
+ this.raf = raf
16
+ this.tags = []
17
+ this.init()
18
+ }
19
+
20
+ init() {
21
+ this.setup()
22
+ this.addEvents()
23
+ }
24
+
25
+ setup() {
26
+ const input = document.createElement('input')
27
+ input.type = 'text'
28
+ input.style.width = this.defaultInputWidth + 'px'
29
+ this.input = input
30
+ this.canvas = document.createElement('canvas')
31
+ this.dom.append(input)
32
+ }
33
+
34
+ getTextWidth(text, font) {
35
+ const context = this.canvas.getContext('2d')
36
+ context.font = font
37
+ const metrics = context.measureText(text)
38
+ return metrics.width
39
+ }
40
+
41
+ getNextInputWidth(textWidth) {
42
+ const { defaultInputWidth } = this
43
+ // spaces before text and after text
44
+ const delta = 5
45
+ const nextWidth = textWidth + delta
46
+ if (nextWidth < defaultInputWidth) {
47
+ return defaultInputWidth
48
+ }
49
+ return nextWidth
50
+ }
51
+
52
+ shake() {
53
+ this.dom.classList.add('shake')
54
+ setTimeout(() => {
55
+ this.dom.classList.remove('shake')
56
+ }, 500)
57
+ }
58
+
59
+ async addTagIfNeeded(value) {
60
+ const { input } = this
61
+ const inputValue = input.value
62
+ const res = await this.validate(inputValue)
63
+ if (! res.isTag) {
64
+ return this.shake()
65
+ }
66
+ const classname = res.classname ? ` ${res.classname}` : ''
67
+ const tag = document.createElement('div')
68
+
69
+ tag.className = 'tag' + classname
70
+ tag.textContent = inputValue
71
+
72
+ const btn = document.createElement('button')
73
+ btn.type = 'button'
74
+
75
+ // https://wesbos.com/times-html-entity-close-button
76
+ btn.textContent = '×'
77
+ const handleBtnClick = () => {
78
+ this.tags = this.tags.filter(row => row.elem !== tag)
79
+ btn.removeEventListener('click', handleBtnClick)
80
+ tag.remove()
81
+ this.change(this.tags.slice())
82
+ }
83
+ btn.addEventListener('click', handleBtnClick)
84
+ tag.appendChild(btn)
85
+
86
+ this.tags.push({ elem: tag, remove: handleBtnClick, res })
87
+ this.dom.insertBefore(tag, input)
88
+ input.value = ''
89
+
90
+ this.change(this.tags.slice())
91
+ }
92
+
93
+ removeTagIfNeeded() {
94
+ const lastTag = this.tags[this.tags.length - 1]
95
+ if ((this.input.value === '') && lastTag) {
96
+ lastTag.remove()
97
+ }
98
+ }
99
+
100
+ addEvents() {
101
+ const { input } = this
102
+ const font = window.getComputedStyle(input)
103
+ .getPropertyValue('font')
104
+
105
+ this.addEvent(this.dom, 'click', event => {
106
+ if (event.target === this.dom) {
107
+ this.input.focus()
108
+ }
109
+ })
110
+
111
+ this.addEvent(input, 'compositionstart', event => {
112
+ this.isComposing = true
113
+ })
114
+
115
+ this.addEvent(input, 'compositionend', event => {
116
+ this.isComposing = false
117
+ })
118
+
119
+ let lastValue = ''
120
+
121
+ this.addEvent(input, 'keydown', async event => {
122
+ const key = getKey(event)
123
+ if ((key === 'enter') && (! this.isComposing)) {
124
+ await this.addTagIfNeeded(input.value)
125
+ }
126
+ else if ((key === 'backspace') && (lastValue === '')) {
127
+ this.removeTagIfNeeded()
128
+ }
129
+ lastValue = input.value
130
+ })
131
+
132
+ this.addEvent(input, 'input', event => {
133
+ this.raf(() => {
134
+ const textWidth = this.getTextWidth(input.value, font)
135
+ const nextWidth = this.getNextInputWidth(textWidth)
136
+ input.style.width = nextWidth + 'px'
137
+ })
138
+ })
139
+ }
140
+
141
+ destroy() {
142
+ this.tags.forEach(tag => tag.remove())
143
+ this.input.remove()
144
+ }
145
+ }
@@ -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';
@@ -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.229
4
+ version: 0.0.230
5
5
  platform: ruby
6
6
  authors:
7
7
  - kmsheng
@@ -144,6 +144,7 @@ files:
144
144
  - src/js/components/SearchDropdown.js
145
145
  - src/js/components/Sidebar.js
146
146
  - src/js/components/Tabbox.js
147
+ - src/js/components/TagInput.js
147
148
  - src/js/components/TimeInput.js
148
149
  - src/js/components/TimeMenu.js
149
150
  - src/js/components/Timepicker.js
@@ -194,11 +195,14 @@ files:
194
195
  - src/js/utils/index.js
195
196
  - src/js/utils/isDef.js
196
197
  - src/js/utils/isInt.js
198
+ - src/js/utils/isStr.js
197
199
  - src/js/utils/isTouchDevice.js
198
200
  - src/js/utils/isUndef.js
199
201
  - src/js/utils/msToS.js
200
202
  - src/js/utils/promisify.js
203
+ - src/js/utils/raf.js
201
204
  - src/js/utils/unbindAll.js
205
+ - src/sass/_animations.scss
202
206
  - src/sass/_beyond-sprockets.scss
203
207
  - src/sass/_beyond.scss
204
208
  - src/sass/_main.scss
@@ -239,6 +243,7 @@ files:
239
243
  - src/sass/components/_switch.scss
240
244
  - src/sass/components/_tabbox.scss
241
245
  - src/sass/components/_table.scss
246
+ - src/sass/components/_tag-input.scss
242
247
  - src/sass/components/_tag.scss
243
248
  - src/sass/components/_time-input.scss
244
249
  - src/sass/components/_time-menu.scss