@stonecrop/aform 0.2.16 → 0.2.18

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.
@@ -10,6 +10,7 @@
10
10
  @keydown.down="onArrowDown"
11
11
  @keydown.up="onArrowUp"
12
12
  @keydown.enter="onEnter" />
13
+
13
14
  <ul id="autocomplete-results" v-show="isOpen" class="autocomplete-results">
14
15
  <li class="loading autocomplete-result" v-if="isLoading">Loading results...</li>
15
16
  <li
@@ -27,111 +28,95 @@
27
28
  </div>
28
29
  </template>
29
30
 
30
- <script lang="ts">
31
- import { defineComponent } from 'vue'
32
- export default defineComponent({
33
- name: 'ADropdown',
34
- props: {
35
- modelValue: {
36
- type: String,
37
- required: false,
38
- default: '',
39
- },
40
- label: {
41
- type: String,
42
- required: true,
43
- },
44
- value: String,
45
- items: {
46
- type: Array,
47
- required: false,
48
- default: () => [],
49
- },
50
- isAsync: {
51
- type: Boolean,
52
- required: false,
53
- default: false,
54
- },
55
- },
56
- emits: ['update:modelValue', 'filterChanged'],
57
- data() {
58
- return {
59
- results: [],
60
- search: this.modelValue,
61
- isLoading: false,
62
- arrowCounter: 0,
63
- isOpen: false,
64
- }
65
- },
66
- watch: {
67
- items: function (value, oldValue) {
68
- this.isLoading = false
69
- this.results = value
70
- },
71
- },
72
- mounted() {
73
- document.addEventListener('click', this.handleClickOutside)
74
- this.filterResults()
75
- },
76
- destroyed() {
77
- document.removeEventListener('click', this.handleClickOutside)
78
- },
79
- methods: {
80
- setResult(result) {
81
- this.search = result
82
- this.closeResults()
83
- },
84
- filterResults() {
85
- this.results = this.items.filter(item => {
86
- return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1
87
- })
88
- },
89
- onChange() {
90
- this.isOpen = true
91
- if (this.isAsync) {
92
- this.isLoading = true
93
- this.$emit('filterChanged', this.search)
94
- } else {
95
- this.filterResults()
96
- }
97
- },
98
- handleClickOutside(event) {
99
- if (!this.$el.contains(event.target)) {
100
- this.closeResults()
101
- this.arrowCounter = 0
102
- }
103
- },
104
- closeResults() {
105
- this.isOpen = false
106
-
107
- if (!this.items.includes(this.search)) {
108
- this.search = ''
109
- }
110
-
111
- this.$emit('update:modelValue', this.search)
112
- },
113
- onArrowDown() {
114
- if (this.arrowCounter < this.results.length) {
115
- this.arrowCounter = this.arrowCounter + 1
116
- }
117
- },
118
- onArrowUp() {
119
- if (this.arrowCounter > 0) {
120
- this.arrowCounter = this.arrowCounter - 1
121
- }
122
- },
123
- onEnter() {
124
- this.search = this.results[this.arrowCounter]
125
- this.closeResults()
126
- this.arrowCounter = 0
127
- },
128
- openWithSearch() {
129
- this.search = ''
130
- this.onChange()
131
- this.$refs.mopInput.focus()
132
- },
133
- },
31
+ <script setup lang="ts">
32
+ import { onMounted, onUnmounted, ref } from 'vue'
33
+
34
+ const props = defineProps<{
35
+ label: string
36
+ items?: string[]
37
+ isAsync?: boolean
38
+ }>()
39
+
40
+ const emit = defineEmits(['filterChanged'])
41
+
42
+ const results = ref(props.items)
43
+ const search = defineModel<string>()
44
+ const isLoading = ref(false)
45
+ const arrowCounter = ref(0)
46
+ const isOpen = ref(false)
47
+ const mopInput = ref(null)
48
+
49
+ onMounted(() => {
50
+ document.addEventListener('click', handleClickOutside)
51
+ filterResults()
52
+ })
53
+
54
+ onUnmounted(() => {
55
+ document.removeEventListener('click', handleClickOutside)
134
56
  })
57
+
58
+ const setResult = result => {
59
+ search.value = result
60
+ closeResults()
61
+ }
62
+
63
+ const filterResults = () => {
64
+ if (!search.value) {
65
+ results.value = props.items
66
+ } else {
67
+ results.value = props.items.filter(item => {
68
+ return item.toLowerCase().indexOf(search.value.toLowerCase()) > -1
69
+ })
70
+ }
71
+ }
72
+
73
+ const onChange = () => {
74
+ isOpen.value = true
75
+ if (props.isAsync) {
76
+ isLoading.value = true
77
+ emit('filterChanged', search.value)
78
+ } else {
79
+ filterResults()
80
+ }
81
+ }
82
+
83
+ const handleClickOutside = (event: MouseEvent) => {
84
+ closeResults()
85
+ arrowCounter.value = 0
86
+ }
87
+
88
+ const closeResults = () => {
89
+ isOpen.value = false
90
+
91
+ // TODO: (test) when would this occur? how should this be tested?
92
+ if (!props.items.includes(search.value)) {
93
+ search.value = ''
94
+ }
95
+ }
96
+
97
+ const onArrowDown = () => {
98
+ if (arrowCounter.value < results.value.length) {
99
+ arrowCounter.value = arrowCounter.value + 1
100
+ }
101
+ }
102
+
103
+ const onArrowUp = () => {
104
+ if (arrowCounter.value > 0) {
105
+ arrowCounter.value = arrowCounter.value - 1
106
+ }
107
+ }
108
+
109
+ const onEnter = () => {
110
+ search.value = results.value[arrowCounter.value]
111
+ closeResults()
112
+ arrowCounter.value = 0
113
+ }
114
+
115
+ // const openWithSearch = () => {
116
+ // search.value = ''
117
+ // onChange()
118
+ // mopInput.value.focus()
119
+ // }
135
120
  </script>
136
121
 
137
122
  <style>
@@ -25,8 +25,8 @@ const props = defineProps<{
25
25
  }>()
26
26
 
27
27
  const formData = ref(props.data || [])
28
- let collapsed = ref(false)
29
- let collapsible = ref(props.collapsible)
28
+ const collapsed = ref(false)
29
+ const collapsible = ref(props.collapsible)
30
30
 
31
31
  const formSchema = ref(props.schema)
32
32
  function toggleCollapse(event: Event) {
@@ -12,66 +12,34 @@
12
12
  </div>
13
13
  </template>
14
14
 
15
- <script lang="ts">
16
- import { defineComponent, inject, PropType, ref, computed } from 'vue'
15
+ <script setup lang="ts">
16
+ import { inject, ref } from 'vue'
17
17
 
18
18
  import { FormSchema } from 'types'
19
- import { useStringMask } from '@/directives/mask'
19
+ import { useStringMask as vMask } from '@/directives/mask'
20
20
 
21
- // TODO: when moving to composition API, figure out how to provide mask
22
- // as a custom directive
23
- export default defineComponent({
24
- name: 'ATextInput',
25
- props: {
26
- schema: {
27
- type: Object as PropType<FormSchema>,
28
- required: true,
29
- },
30
- label: {
31
- type: String,
32
- required: true,
33
- },
34
- modelValue: {
35
- type: null as unknown as PropType<string | number>,
36
- },
37
- mask: {
38
- type: String,
39
- },
40
- required: {
41
- type: Boolean,
42
- },
43
- readonly: {
44
- type: Boolean,
45
- },
46
- uuid: {
47
- type: String,
48
- },
49
- validation: {
50
- type: Object,
51
- default: () => ({ errorMessage: '&nbsp;' }),
52
- },
53
- },
54
- setup(props, context) {
55
- const maskFilled = ref(false)
21
+ withDefaults(
22
+ defineProps<{
23
+ schema: FormSchema
24
+ label: string
25
+ mask?: string
26
+ required?: boolean
27
+ readonly?: boolean
28
+ uuid?: string
29
+ validation?: { errorMessage: string }
30
+ }>(),
31
+ {
32
+ validation: () => ({ errorMessage: '&nbsp;' }),
33
+ }
34
+ )
56
35
 
57
- // TODO: (state) replace with state management
58
- const locale = inject<string>('locale', '')
36
+ // TODO: setup maskFilled as a computed property
37
+ const maskFilled = ref(true)
59
38
 
60
- const inputText = computed({
61
- get() {
62
- return props.modelValue
63
- },
64
- set(newValue) {
65
- context.emit('update:modelValue', newValue)
66
- },
67
- })
39
+ // TODO: (state) replace with state management
40
+ // const locale = inject<string>('locale', '')
68
41
 
69
- return { inputText, locale, maskFilled }
70
- },
71
- directives: {
72
- mask: useStringMask,
73
- },
74
- })
42
+ const inputText = defineModel<number | string>()
75
43
  </script>
76
44
 
77
45
  <style scoped>
@@ -17,6 +17,7 @@
17
17
  name="email"
18
18
  placeholder="name@example.com"
19
19
  type="email"
20
+ v-model="email"
20
21
  auto-capitalize="none"
21
22
  auto-complete="email"
22
23
  auto-correct="off"
@@ -25,11 +26,17 @@
25
26
 
26
27
  <div class="login-form-password login-form-element">
27
28
  <label id="login-password" for="password" class="login-label">Password</label>
28
- <input id="password" class="login-field" name="password" type="password" :disabled="isLoading" />
29
+ <input
30
+ id="password"
31
+ class="login-field"
32
+ name="password"
33
+ type="password"
34
+ v-model="password"
35
+ :disabled="isLoading" />
29
36
  </div>
30
37
 
31
- <button class="btn" :disabled="isLoading">
32
- <span v-if="isLoading" class="material-symbols-outlined loading-icon"> progress_activity </span>
38
+ <button class="btn" @click="onSubmit" :disabled="isLoading || !email || !password">
39
+ <span v-if="isLoading" class="material-symbols-outlined loading-icon">progress_activity</span>
33
40
  <span id="login-form-button">Login</span>
34
41
  </button>
35
42
  </div>
@@ -57,13 +64,28 @@ withDefaults(
57
64
  }
58
65
  )
59
66
 
67
+ const emit = defineEmits(['loginFailed', 'loginSuccess'])
68
+
69
+ const email = ref('')
70
+ const password = ref('')
71
+
60
72
  const isLoading = ref(false)
73
+ const loginFailed = ref(false)
61
74
 
62
75
  function onSubmit(event: Event) {
63
76
  event.preventDefault()
64
77
  isLoading.value = true
65
78
 
66
- // TODO: handle submit logic
79
+ // TODO: handle submit logic, handle failure
80
+
81
+ if (loginFailed.value) {
82
+ isLoading.value = false
83
+ emit('loginFailed')
84
+ return
85
+ }
86
+
87
+ isLoading.value = false
88
+ emit('loginSuccess')
67
89
  }
68
90
  </script>
69
91
 
@@ -1,5 +1,5 @@
1
1
  import type { FormSchema } from 'types'
2
- import { DirectiveBinding } from 'vue'
2
+ import type { DirectiveBinding } from 'vue'
3
3
 
4
4
  const NAMED_MASKS = {
5
5
  date: '##/##/####',
@@ -35,7 +35,7 @@ function getMask(binding: DirectiveBinding<string>) {
35
35
  } else {
36
36
  // TODO: (state) handle using state management
37
37
  const schema: FormSchema = binding.instance['schema']
38
- const fieldType: string | undefined = schema.fieldtype?.toLowerCase()
38
+ const fieldType: string | undefined = schema?.fieldtype?.toLowerCase()
39
39
  if (fieldType && NAMED_MASKS[fieldType]) {
40
40
  mask = NAMED_MASKS[fieldType]
41
41
  }