@awes-io/ui 2.42.0 → 2.44.0

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,46 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [2.44.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.43.0...@awes-io/ui@2.44.0) (2022-03-10)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * remove mask import ([5fd53f3](https://github.com/awes-io/client/commit/5fd53f3e5204dd25fdbcbb727111c9d490c74788))
12
+
13
+
14
+ ### Features
15
+
16
+ * replace vue-the-mask with pattern ([a9af187](https://github.com/awes-io/client/commit/a9af18764acee563ca6ec242b9b18dbba95f4542))
17
+ * ui updates ([a2d34b7](https://github.com/awes-io/client/commit/a2d34b77c8a0e0a680066a0a81382b3dc2d7d243))
18
+ * **aw-birthday-picker:** refactor ([79f3459](https://github.com/awes-io/client/commit/79f345921520f91488d5b3c1feafc10c3897ac54))
19
+
20
+
21
+
22
+
23
+
24
+ # [2.43.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.42.1...@awes-io/ui@2.43.0) (2022-02-28)
25
+
26
+
27
+ ### Features
28
+
29
+ * blocked twofactor auth ([dbef9a3](https://github.com/awes-io/client/commit/dbef9a3d9989d8a33ba276a73c3a32ec184b5e5e))
30
+
31
+
32
+
33
+
34
+
35
+ ## [2.42.1](https://github.com/awes-io/client/compare/@awes-io/ui@2.42.0...@awes-io/ui@2.42.1) (2022-02-10)
36
+
37
+
38
+ ### Bug Fixes
39
+
40
+ * locked prop for fixed button ([9e2067a](https://github.com/awes-io/client/commit/9e2067ae0abbbfe766f6ea63d9c2cc26940c90b1))
41
+
42
+
43
+
44
+
45
+
6
46
  # [2.42.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.41.0...@awes-io/ui@2.42.0) (2022-02-01)
7
47
 
8
48
 
@@ -1,18 +1,89 @@
1
1
  .aw-birthday-picker {
2
2
  &__wrap {
3
+ @apply border rounded bg-surface justify-between;
3
4
  display: flex;
4
5
  align-items: center;
5
- gap: theme('spacing.3', 0,75rem);
6
+ text-align: center;
7
+
8
+ &.has-error {
9
+ @apply border-error;
10
+ animation: 700ms shake ease-out-quad;
11
+ }
12
+ }
13
+
14
+ &__input {
15
+ border: none;
16
+ border-radius: 0;
17
+ flex: auto;
18
+
19
+ input {
20
+ text-align: center;
21
+ border-radius: 0;
22
+ }
23
+
24
+ &--day {
25
+ &::before, &::after {
26
+ @apply left-0 top-0 absolute;
27
+ content: '';
28
+ z-index: 1;
29
+ top: 50%;
30
+ transform: translateY(-50%);
31
+ width: 1px;
32
+ height: 100%;
33
+ background-color: rgba(var(--c-on-surface-rgb), 0.1);
34
+ }
35
+
36
+ &::after {
37
+ left: unset;
38
+ right: 0;
39
+ }
40
+ }
6
41
  }
7
42
 
8
- &__day {
43
+
44
+
45
+ /* &__day {
9
46
  min-width: 6rem;
10
47
  flex-basis: 20%;
11
- }
48
+ } */
12
49
 
13
- &__month,
50
+ /* &__month,
14
51
  &__year {
15
52
  min-width: 5rem;
16
53
  flex-basis: 40%;
17
- }
54
+ } */
18
55
  }
56
+
57
+ @keyframes shake {
58
+ 0%,
59
+ 100% {
60
+ transform:translateX(0)
61
+ }
62
+ 10% {
63
+ transform:translateX(-9px)
64
+ }
65
+ 20% {
66
+ transform:translateX(8px)
67
+ }
68
+ 30% {
69
+ transform:translateX(-7px)
70
+ }
71
+ 40% {
72
+ transform:translateX(6px)
73
+ }
74
+ 50% {
75
+ transform:translateX(-5px)
76
+ }
77
+ 60% {
78
+ transform:translateX(4px)
79
+ }
80
+ 70% {
81
+ transform:translateX(-3px)
82
+ }
83
+ 80% {
84
+ transform:translateX(2px)
85
+ }
86
+ 90% {
87
+ transform:translateX(-1px)
88
+ }
89
+ }
@@ -12,7 +12,7 @@
12
12
  letter-spacing: 0.09375rem;
13
13
  text-transform: uppercase;
14
14
 
15
- background-color: rgba(var(--btn-bg), 1);
15
+ background-color: rgba(var(--btn-bg), var(--btn-bg-opacity, 1));
16
16
  color: rgba(var(--btn-fg), 1);
17
17
 
18
18
  box-shadow: 0px 0.25rem 0.5rem rgba(var(--btn-bg), 0.2);
@@ -35,6 +35,32 @@
35
35
  }
36
36
  }
37
37
 
38
+ &__lock {
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+
43
+ position: absolute;
44
+ inset: 0;
45
+
46
+ span {
47
+ background-color: var(--c-surface);
48
+ color: var(--c-on-surface);
49
+
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ border-radius: 50%;
54
+
55
+ padding: 0.32em;
56
+ font-size: 1.2em;
57
+ }
58
+ }
59
+
60
+ &--locked {
61
+ position: relative;
62
+ }
63
+
38
64
  &:hover {
39
65
  background-image: linear-gradient(rgba(var(--btn-fg), 0.15), rgba(var(--btn-fg), 0.15));
40
66
  }
@@ -46,4 +72,10 @@
46
72
  &:focus-visible {
47
73
  outline: theme('focusOutline');
48
74
  }
75
+
76
+ &[disabled] {
77
+ --btn-bg-opacity: 0.5 !important;
78
+ cursor: not-allowed !important;
79
+ user-select: none !important;
80
+ }
49
81
  }
@@ -193,9 +193,9 @@ export default {
193
193
  const isDisabled =
194
194
  Object.keys(this.$attrs).includes('disabled') &&
195
195
  this.$attrs.disabled
196
- const hasTooltip = !!this.errorText
196
+ // const hasTooltip = !!this.errorText /* blocks switcher */
197
197
 
198
- if (this.startPos !== null || isDisabled || hasTooltip) return
198
+ if (this.startPos !== null || isDisabled /* || hasTooltip */) return
199
199
 
200
200
  this.startPos = $event.screenX
201
201
  this.isTouch = $event.type === 'touchstart'
@@ -687,6 +687,7 @@ export default {
687
687
  _selectOnEnter() {
688
688
  // close if nothing typed
689
689
  if (this._showNotFound) {
690
+ this.$emit('not-found', this.searchPhrase)
690
691
  this.searchPhrase = ''
691
692
  this.close()
692
693
  return
@@ -698,9 +699,7 @@ export default {
698
699
  if (firstOption) {
699
700
  this._selectIndex(firstOption.index)
700
701
  } else {
701
- // emit not found
702
702
  this.isOpened = false
703
- this.$emit('not-found', this.searchPhrase)
704
703
  }
705
704
  },
706
705
 
@@ -1,58 +1,55 @@
1
1
  <template>
2
2
  <AwInfo :label="label" class="aw-birthday-picker">
3
- <div class="aw-birthday-picker__wrap">
4
- <AwSelect
5
- v-model="month"
6
- :options="monthsList"
3
+ <label
4
+ ref="element"
5
+ v-tooltip.show.prepend="errorTooltip"
6
+ :class="{ 'has-error': hasError && errorText }"
7
+ class="aw-birthday-picker__wrap"
8
+ >
9
+ <AwInput
10
+ v-model="displayMonth"
7
11
  :required="required"
8
12
  :name="_inputKeys.month"
9
- :label="$t('AwBirthdayPicker.month')"
10
- track-by="value"
11
- option-label="text"
12
- class="aw-birthday-picker__month"
13
- @input="checkMaxDay"
13
+ :placeholder="$t('AwBirthdayPicker.month')"
14
+ pattern="##"
15
+ class="aw-birthday-picker__input"
16
+ inputmode="numeric"
17
+ @focus="onInputFocus"
18
+ @blur="onMonthBlur"
14
19
  />
15
20
 
16
- <AwSelect
17
- v-model="day"
18
- :options="daysList"
21
+ <AwInput
22
+ ref="dayInput"
23
+ v-model="displayDay"
19
24
  :required="required"
20
25
  :name="_inputKeys.day"
21
- :label="$t('AwBirthdayPicker.day')"
22
- class="aw-birthday-picker__day"
23
- @input="emit"
26
+ :placeholder="$t('AwBirthdayPicker.day')"
27
+ pattern="##"
28
+ inputmode="numeric"
29
+ class="aw-birthday-picker__input aw-birthday-picker__input--day"
30
+ @focus="onInputFocus"
31
+ @blur="onDayBlur"
24
32
  />
25
33
 
26
- <div class="aw-birthday-picker__year">
27
- <AwLink
28
- v-if="!_showYear"
29
- :text="$t('AwBirthdayPicker.set_year')"
30
- @click="isYearHidden = false"
31
- />
32
-
33
- <AwSelect
34
- v-else
35
- v-model="year"
36
- :options="yearsList"
37
- :required="required"
38
- :name="_inputKeys.year"
39
- :label="$t('AwBirthdayPicker.year')"
40
- :clearable="!showYear"
41
- :option-disabled="isOptionDisabled"
42
- class="w-full"
43
- track-by="year"
44
- option-label="year"
45
- @input="checkMaxDay"
46
- @clear="clearYear"
47
- />
48
- </div>
49
- </div>
34
+ <AwInput
35
+ ref="yearInput"
36
+ v-model="year"
37
+ :required="required"
38
+ :name="_inputKeys.year"
39
+ :placeholder="$t('AwBirthdayPicker.year')"
40
+ pattern="####"
41
+ class="aw-birthday-picker__input"
42
+ inputmode="numeric"
43
+ @input="onYearInput"
44
+ @focus="onInputFocus"
45
+ />
46
+ </label>
50
47
  </AwInfo>
51
48
  </template>
52
49
 
53
50
  <script>
54
51
  import birthdayMixin from '@AwMixins/birthday'
55
- import { isNil } from 'rambdax'
52
+ import ErrorMixin from '@AwMixins/error'
56
53
 
57
54
  const DEFAULT_KEYS = {
58
55
  day: 'birthday_day',
@@ -63,7 +60,7 @@ const DEFAULT_KEYS = {
63
60
  export default {
64
61
  name: 'AwBirthdayPicker',
65
62
 
66
- mixins: [birthdayMixin],
63
+ mixins: [birthdayMixin, ErrorMixin],
67
64
 
68
65
  props: {
69
66
  value: {
@@ -106,48 +103,19 @@ export default {
106
103
  month: null,
107
104
  day: null,
108
105
  year: null,
109
- isYearHidden: true
106
+ maxDay: 31,
107
+ displayDay: null,
108
+ displayMonth: null,
109
+ inputTimeout: null
110
110
  }
111
111
  },
112
112
 
113
113
  computed: {
114
- _showYear() {
115
- return this.showYear || !this.isYearHidden
116
- },
117
-
118
114
  _inputKeys() {
119
115
  return {
120
116
  ...DEFAULT_KEYS,
121
117
  ...this.inputNames
122
118
  }
123
- },
124
-
125
- monthsList() {
126
- const date = this.$dayjs()
127
- return [...Array(12).keys()].map((el) => ({
128
- value: el,
129
- text: date.month(el).format('MMMM')
130
- }))
131
- },
132
-
133
- daysList() {
134
- const date = this.$dayjs().year(this.year || 2000)
135
-
136
- const maxDays = date.month(this.month || 0).daysInMonth()
137
-
138
- const arr = [...Array(maxDays + 1).keys()]
139
- arr.shift()
140
- return arr
141
- },
142
-
143
- yearsList() {
144
- const current = this.$dayjs().year()
145
- return [...Array(101).keys()].map((el) => ({
146
- year: current - el,
147
- isLeapYear: this.$dayjs()
148
- .year(current - el)
149
- .isLeapYear()
150
- }))
151
119
  }
152
120
  },
153
121
 
@@ -157,32 +125,130 @@ export default {
157
125
  handler(val) {
158
126
  const date = this.parseDate(val)
159
127
  if (date) {
160
- this.month = date.month
128
+ this.month = date.month + 1
161
129
  this.day = date.day
162
- this.year = date.year
163
130
  this.isYearHidden = !date.year
131
+ let d = this.$dayjs()
132
+ .year(2000)
133
+ .month(date.month)
134
+ .date(date.day)
135
+ .startOf('day')
136
+
137
+ if (date.year) {
138
+ this.year = date.year
139
+ d = d.year(date.year)
140
+ }
141
+
142
+ this.displayDay = d.format('DD')
143
+ this.displayMonth = d.format('MM')
164
144
  }
165
145
  }
146
+ },
147
+
148
+ displayMonth(val) {
149
+ if (val && val.length == 2) {
150
+ this.$refs['dayInput'].$el.focus()
151
+ }
152
+ },
153
+
154
+ displayDay(val) {
155
+ if (val && val.length == 2) {
156
+ this.$refs['yearInput'].$el.focus()
157
+ }
166
158
  }
167
159
  },
168
160
 
169
161
  methods: {
170
162
  checkMaxDay() {
171
- const maxDay = this.daysList[this.daysList.length - 1]
172
- this.day = this.day > maxDay ? maxDay : this.day
163
+ if (this.day) {
164
+ const m = this.month || 1
165
+ let d = this.$dayjs()
166
+ .year(this.year || 2000)
167
+ .month(m - 1)
168
+ .startOf('month')
169
+
170
+ this.maxDay = d.daysInMonth()
171
+ this.day = this.day > this.maxDay ? this.maxDay : this.day
172
+
173
+ this.displayDay = d
174
+ .date(this.day)
175
+ .startOf('day')
176
+ .format('DD')
177
+ }
178
+
173
179
  this.emit()
174
180
  },
175
181
 
182
+ onMonthBlur() {
183
+ const val = parseInt(this.displayMonth)
184
+
185
+ if (isNaN(val)) {
186
+ this.month = null
187
+ this.displayMonth = null
188
+ this.checkMaxDay()
189
+ return
190
+ }
191
+
192
+ if (val !== this.month) {
193
+ if (val > 12) {
194
+ this.month = 12
195
+ } else {
196
+ this.month = val
197
+ }
198
+
199
+ this.checkMaxDay()
200
+ }
201
+
202
+ const d = this.$dayjs()
203
+ .year(this.year || 2000)
204
+ .month(this.month - 1)
205
+ .startOf('month')
206
+ this.displayMonth = d.format('MM')
207
+ },
208
+
209
+ onDayBlur(e) {
210
+ const val = parseInt(e.target.value)
211
+
212
+ if (isNaN(val)) {
213
+ this.day = null
214
+ this.displayDay = null
215
+ this.emit()
216
+ return
217
+ }
218
+
219
+ if (val === this.day) {
220
+ return
221
+ }
222
+
223
+ this.day = val
224
+ this.checkMaxDay()
225
+ },
226
+
227
+ onInputFocus(e) {
228
+ if (e.target.value) {
229
+ e.target.setSelectionRange(0, e.target.value.length)
230
+ }
231
+ },
232
+
233
+ onYearInput() {
234
+ clearTimeout(this.inputTimeout)
235
+ this.inputTimeout = setTimeout(() => {
236
+ this.checkMaxDay()
237
+ }, 200)
238
+ },
239
+
176
240
  emit() {
177
- if (!isNil(this.month) && this.day) {
241
+ if (!this.month || !this.day) {
242
+ this.$emit('input', null)
243
+ } else if (this.month && this.day) {
178
244
  let d = this.$dayjs()
179
245
  .year(this.year || 2000)
180
- .month(this.month)
246
+ .month(this.month - 1)
181
247
  .date(this.day)
248
+ .startOf('day')
182
249
  let formatVal = this.shortParseFormat || 'MM-DD'
183
250
 
184
- if (!this.isYearHidden && this.year) {
185
- d = d.year(this.year)
251
+ if (this.year) {
186
252
  formatVal = this.fullParseFormat || null
187
253
  }
188
254
 
@@ -191,20 +257,6 @@ export default {
191
257
  formatVal ? d.format(formatVal) : d.format()
192
258
  )
193
259
  }
194
- },
195
-
196
- clearYear() {
197
- this.isYearHidden = true
198
- this.year = null
199
- this.emit()
200
- },
201
-
202
- isOptionDisabled(option) {
203
- if (this.month === 1 && this.day === 29) {
204
- return !option.isLeapYear
205
- }
206
-
207
- return false
208
260
  }
209
261
  }
210
262
  }
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div class="aw-date" @click="onDateClick">
3
3
  <AwInput
4
+ ref="input"
4
5
  v-bind="{ ...$attrs, label, id }"
5
6
  :value="inputValue"
6
7
  :prefix="prefix"
@@ -192,6 +193,10 @@ export default {
192
193
 
193
194
  watch: {
194
195
  value(value) {
196
+ if (this.$refs.input && this.$refs.input.hasError) {
197
+ this.$refs.input.setError('')
198
+ }
199
+
195
200
  if (value !== null && this.isOpened) {
196
201
  this.isOpened = false
197
202
  }
@@ -1,8 +1,10 @@
1
1
  <template>
2
2
  <Component
3
- :is="_linkComponent"
3
+ :is="locked ? 'button' : _linkComponent"
4
4
  v-bind="_linkAttrs"
5
5
  :style="buttonStyle"
6
+ :disabled="_linkAttrs.disabled || locked"
7
+ :class="{ 'aw-button-fixed--locked': locked }"
6
8
  class="aw-button-fixed"
7
9
  v-on="$listeners"
8
10
  >
@@ -16,6 +18,15 @@
16
18
  <slot name="icon">
17
19
  <AwIcon :name="icon" size="24" class="flex-shrink-0" />
18
20
  </slot>
21
+ <span
22
+ v-if="locked"
23
+ class="aw-button-fixed__lock"
24
+ v-tooltip="lockedTooltip"
25
+ >
26
+ <span>
27
+ <AwIconSystemMono name="lock" />
28
+ </span>
29
+ </span>
19
30
  </Component>
20
31
  </template>
21
32
 
package/mixins/button.js CHANGED
@@ -3,6 +3,15 @@ export default {
3
3
  color: {
4
4
  type: String,
5
5
  default: 'accent'
6
+ },
7
+
8
+ // Show lock icon and disable button
9
+ locked: Boolean,
10
+
11
+ // Tooltip when button is locked
12
+ lockedTooltip: {
13
+ type: String,
14
+ default: ''
6
15
  }
7
16
  },
8
17
 
@@ -56,7 +56,7 @@ i18nOptions.messages = mergeDeepRight(messages, i18nOptions.messages || {})
56
56
  const beforeListeners = new Map()
57
57
  const afterListeners = new Map()
58
58
 
59
- export default async ({ app }) => {
59
+ export default async ({ app, $axios }) => {
60
60
  const locales = langOptions.locales.slice().map(locale => {
61
61
  if (isType('String', locale)) {
62
62
  return { code: locale }
@@ -137,7 +137,7 @@ export default async ({ app }) => {
137
137
  if (loadedLocales[locale]) return loadedLocales[locale]
138
138
 
139
139
  const requestConfig = isType('Function', fetchTranslation)
140
- ? fetchTranslation(locale)
140
+ ? fetchTranslation(locale, locales.find(({ code }) => code === locale))
141
141
  : { url: fetchTranslation }
142
142
 
143
143
  try {
@@ -157,6 +157,9 @@ export default async ({ app }) => {
157
157
  app.i18n.setLocale = async locale => {
158
158
  const oldLocale = app.i18n.locale
159
159
 
160
+ // Update Accept-Language header
161
+ $axios.defaults.headers.common['Accept-Language'] = locale
162
+
160
163
  for (const beforeListener of beforeListeners.keys()) {
161
164
  await beforeListener(locale, oldLocale)
162
165
  }
@@ -179,6 +182,11 @@ export default async ({ app }) => {
179
182
  }
180
183
  }
181
184
 
185
+ /**
186
+ * Set Accept-Language header
187
+ */
188
+ $axios.defaults.headers.common['Accept-Language'] = app.i18n.locale
189
+
182
190
  /**
183
191
  * Set language on init
184
192
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awes-io/ui",
3
- "version": "2.42.0",
3
+ "version": "2.44.0",
4
4
  "description": "User Interface (UI) components",
5
5
  "keywords": [
6
6
  "ui",
@@ -124,5 +124,5 @@
124
124
  "vue-template-compiler": "^2.6.10",
125
125
  "webfonts-generator": "^0.4.0"
126
126
  },
127
- "gitHead": "0e090b4bf9900be85106e5edc3940299809e5971"
127
+ "gitHead": "fce6417d348bb3e187df9c4ea498562055ee5c31"
128
128
  }