beyond-rails 0.0.229 → 0.0.230
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 +4 -4
- data/src/js/components/TagInput.js +145 -0
- data/src/js/decorators/chartCommon.js +6 -8
- data/src/js/index.js +2 -0
- data/src/js/utils/getKey.js +1 -0
- data/src/js/utils/isStr.js +3 -0
- data/src/js/utils/raf.js +8 -0
- data/src/sass/_animations.scss +13 -0
- data/src/sass/_beyond.scss +2 -0
- data/src/sass/components/_tag-input.scss +26 -0
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf80575d0a2ac63e76f75b053115cd6c5518382878d406745c4f959d602d2767
|
4
|
+
data.tar.gz: b4c4372056bc1e9d5deddafbf62cadb8ab5ac8f53e3761a36f876b8b4db3897d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 => {
|
data/src/js/index.js
CHANGED
@@ -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,
|
data/src/js/utils/getKey.js
CHANGED
data/src/js/utils/raf.js
ADDED
@@ -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
|
+
}
|
data/src/sass/_beyond.scss
CHANGED
@@ -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.
|
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
|