@stonecrop/aform 0.2.11 → 0.2.13
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/package.json +5 -5
- package/src/components/form/ADate.vue +74 -257
- package/src/components/form/ADatePicker.vue +160 -0
- package/src/histoire.setup.ts +4 -0
- package/src/index.ts +3 -1
- package/src/theme/adate.css +49 -0
- package/dist/aform.js +0 -869
- package/dist/aform.js.map +0 -1
- package/dist/aform.umd.cjs +0 -2
- package/dist/aform.umd.cjs.map +0 -1
- package/dist/style.css +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/aform",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"uuid": "^9.0.0",
|
|
35
35
|
"vue": "^3.4.23",
|
|
36
|
-
"@stonecrop/themes": "0.2.
|
|
37
|
-
"@stonecrop/utilities": "0.2.
|
|
36
|
+
"@stonecrop/themes": "0.2.13",
|
|
37
|
+
"@stonecrop/utilities": "0.2.13"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@histoire/plugin-vue": "^0.17.17",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"vite": "^5.2.9",
|
|
56
56
|
"vitest": "^1.5.0",
|
|
57
57
|
"vue-router": "^4",
|
|
58
|
-
"@stonecrop/atable": "0.2.
|
|
58
|
+
"@stonecrop/atable": "0.2.13"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@stonecrop/atable": "0.2.
|
|
61
|
+
"@stonecrop/atable": "0.2.13"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|
|
@@ -1,277 +1,94 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
<td @click="previousMonth" :tabindex="-1"><</td>
|
|
14
|
-
<th colspan="5">{{ monthAndYear }}</th>
|
|
15
|
-
<td @click="nextMonth" :tabindex="-1">></td>
|
|
16
|
-
</tr>
|
|
17
|
-
<tr v-for="rowNo in numberOfRows" :key="rowNo">
|
|
18
|
-
<!-- TODO: (style) remove inline styling and replace with theme package -->
|
|
19
|
-
<td
|
|
20
|
-
v-for="colNo in numberOfColumns"
|
|
21
|
-
:key="(rowNo - 1) * numberOfColumns + colNo"
|
|
22
|
-
:contenteditable="false"
|
|
23
|
-
:spellcheck="false"
|
|
24
|
-
:tabindex="0"
|
|
25
|
-
:style="{
|
|
26
|
-
border: isSelectedDate(currentDates[(rowNo - 1) * numberOfColumns + colNo])
|
|
27
|
-
? '2px solid var(--focus-cell-outline)'
|
|
28
|
-
: 'none',
|
|
29
|
-
borderBottomColor: isTodaysDate(currentDates[(rowNo - 1) * numberOfColumns + colNo])
|
|
30
|
-
? 'var(--focus-cell-outline)'
|
|
31
|
-
: 'none',
|
|
32
|
-
}"
|
|
33
|
-
@click.prevent.stop="selectDate($event, (rowNo - 1) * numberOfColumns + colNo)"
|
|
34
|
-
:class="{
|
|
35
|
-
todaysdate: isTodaysDate(currentDates[(rowNo - 1) * numberOfColumns + colNo]),
|
|
36
|
-
selecteddate: isSelectedDate(currentDates[(rowNo - 1) * numberOfColumns + colNo]),
|
|
37
|
-
}">
|
|
38
|
-
{{ new Date(currentDates[(rowNo - 1) * numberOfColumns + colNo]).getDate() }}
|
|
39
|
-
</td>
|
|
40
|
-
</tr>
|
|
41
|
-
</table>
|
|
2
|
+
<div>
|
|
3
|
+
<input
|
|
4
|
+
ref="dateRef"
|
|
5
|
+
type="date"
|
|
6
|
+
:id="uuid"
|
|
7
|
+
:disabled="readonly"
|
|
8
|
+
:required="required"
|
|
9
|
+
:value="inputDate"
|
|
10
|
+
@click="showPicker" />
|
|
11
|
+
<label :for="uuid">{{ label }}</label>
|
|
12
|
+
<p v-show="validation.errorMessage" v-html="validation.errorMessage"></p>
|
|
42
13
|
</div>
|
|
43
14
|
</template>
|
|
44
15
|
|
|
45
16
|
<script setup lang="ts">
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}>()
|
|
59
|
-
|
|
60
|
-
const tableData = inject<TableDataStore>(props.tableid)
|
|
61
|
-
|
|
62
|
-
const numberOfRows = 6
|
|
63
|
-
const numberOfColumns = 7
|
|
64
|
-
const todaysDate = new Date()
|
|
65
|
-
|
|
66
|
-
const selectedDate = ref<Date>()
|
|
67
|
-
const currentMonth = ref<number>()
|
|
68
|
-
const currentYear = ref<number>()
|
|
69
|
-
const currentDates = ref<number[]>([])
|
|
70
|
-
// const width = ref('')
|
|
71
|
-
|
|
72
|
-
onMounted(async () => {
|
|
73
|
-
let cellDate = tableData.cellData<string | number | Date>(props.colIndex, props.rowIndex)
|
|
74
|
-
if (cellDate) {
|
|
75
|
-
if (!(cellDate instanceof Date)) {
|
|
76
|
-
cellDate = new Date(cellDate)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
selectedDate.value = cellDate
|
|
80
|
-
currentMonth.value = selectedDate.value.getMonth()
|
|
81
|
-
currentYear.value = selectedDate.value.getFullYear()
|
|
82
|
-
} else {
|
|
83
|
-
currentMonth.value = todaysDate.getMonth()
|
|
84
|
-
currentYear.value = todaysDate.getFullYear()
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
renderMonth()
|
|
88
|
-
await nextTick()
|
|
89
|
-
|
|
90
|
-
const $selectedDate = document.getElementsByClassName('selecteddate')
|
|
91
|
-
if ($selectedDate.length > 0) {
|
|
92
|
-
;($selectedDate[0] as HTMLElement).focus()
|
|
93
|
-
} else {
|
|
94
|
-
const $todaysDate = document.getElementsByClassName('todaysdate')
|
|
95
|
-
if ($todaysDate.length > 0) {
|
|
96
|
-
;($todaysDate[0] as HTMLElement).focus()
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
watch([currentMonth, currentYear], () => {
|
|
102
|
-
renderMonth()
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const renderMonth = () => {
|
|
106
|
-
currentDates.value = []
|
|
107
|
-
const firstOfMonth = new Date(currentYear.value, currentMonth.value, 1)
|
|
108
|
-
const monthStartWeekday = firstOfMonth.getDay()
|
|
109
|
-
const calendarStartDay = firstOfMonth.setDate(firstOfMonth.getDate() - monthStartWeekday)
|
|
110
|
-
for (let dayIndex of Array(43).keys()) {
|
|
111
|
-
currentDates.value.push(calendarStartDay + dayIndex * 86400000)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const previousYear = () => {
|
|
116
|
-
currentYear.value -= 1
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const nextYear = () => {
|
|
120
|
-
currentYear.value += 1
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const previousMonth = () => {
|
|
124
|
-
if (currentMonth.value == 0) {
|
|
125
|
-
currentMonth.value = 11
|
|
126
|
-
previousYear()
|
|
127
|
-
} else {
|
|
128
|
-
currentMonth.value -= 1
|
|
17
|
+
import { ref } from 'vue'
|
|
18
|
+
|
|
19
|
+
withDefaults(
|
|
20
|
+
defineProps<{
|
|
21
|
+
label: string
|
|
22
|
+
required?: boolean
|
|
23
|
+
readonly?: boolean
|
|
24
|
+
uuid?: string
|
|
25
|
+
validation?: Record<string, any>
|
|
26
|
+
}>(),
|
|
27
|
+
{
|
|
28
|
+
validation: () => ({ errorMessage: ' ' }),
|
|
129
29
|
}
|
|
130
|
-
|
|
30
|
+
)
|
|
131
31
|
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
currentMonth.value = 0
|
|
135
|
-
nextYear()
|
|
136
|
-
} else {
|
|
137
|
-
currentMonth.value += 1
|
|
138
|
-
}
|
|
139
|
-
}
|
|
32
|
+
const inputDate = defineModel<string | number | Date>()
|
|
33
|
+
const dateRef = ref<HTMLInputElement | null>(null)
|
|
140
34
|
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
|
|
35
|
+
const showPicker = () => {
|
|
36
|
+
if (dateRef.value) {
|
|
37
|
+
dateRef.value.showPicker()
|
|
144
38
|
}
|
|
145
|
-
return todaysDate.toDateString() === new Date(day).toDateString()
|
|
146
39
|
}
|
|
147
|
-
|
|
148
|
-
const isSelectedDate = (day: string | number | Date) => {
|
|
149
|
-
return new Date(day).toDateString() === new Date(selectedDate.value).toDateString()
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const selectDate = (event: Event, currentIndex: number) => {
|
|
153
|
-
selectedDate.value = new Date(currentDates.value[currentIndex])
|
|
154
|
-
updateData()
|
|
155
|
-
// TODO: (typing) figure out a way to close datepicker
|
|
156
|
-
// context.refs.adatepicker.destroy()
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const updateData = () => {
|
|
160
|
-
// TODO: check proper date format to feed back (assuming number for now)
|
|
161
|
-
tableData.setCellData(props.rowIndex, props.colIndex, selectedDate.value.getTime())
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// const dayWidth = computed(() => {
|
|
165
|
-
// const widthValue = Number(width.value.replace('px', ''))
|
|
166
|
-
// return `${widthValue / (numberOfColumns - 1)}px`
|
|
167
|
-
// })
|
|
168
|
-
|
|
169
|
-
const monthAndYear = computed(() => {
|
|
170
|
-
return new Date(currentYear.value, currentMonth.value, 1).toLocaleDateString(undefined, {
|
|
171
|
-
year: 'numeric',
|
|
172
|
-
month: 'long',
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// setup keyboard navigation
|
|
177
|
-
useKeyboardNav([
|
|
178
|
-
{
|
|
179
|
-
parent: 'table.adate',
|
|
180
|
-
selectors: 'td',
|
|
181
|
-
handlers: {
|
|
182
|
-
...defaultKeypressHandlers,
|
|
183
|
-
...{
|
|
184
|
-
'keydown.pageup': previousMonth,
|
|
185
|
-
'keydown.shift.pageup': previousYear,
|
|
186
|
-
'keydown.pagedown': nextMonth,
|
|
187
|
-
'keydown.shift.pagedown': nextYear,
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
])
|
|
192
40
|
</script>
|
|
193
41
|
|
|
194
42
|
<style scoped>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
43
|
+
div {
|
|
44
|
+
min-width: 40ch;
|
|
45
|
+
border: 1px solid transparent;
|
|
46
|
+
padding: 0rem;
|
|
47
|
+
margin: 0rem;
|
|
48
|
+
margin-right: 1ch;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
input {
|
|
52
|
+
width: calc(100% - 1ch);
|
|
53
|
+
outline: 1px solid transparent;
|
|
54
|
+
border: 1px solid var(--input-border-color);
|
|
55
|
+
padding: 1ch 0.5ch 0.5ch 1ch;
|
|
56
|
+
margin: calc(1.15rem / 2) 0 0 0;
|
|
57
|
+
min-height: 1.15rem;
|
|
58
|
+
border-radius: 0.25rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
p,
|
|
62
|
+
label {
|
|
63
|
+
color: var(--input-label-color);
|
|
64
|
+
display: block;
|
|
65
|
+
min-height: 1.15rem;
|
|
66
|
+
padding: 0rem;
|
|
67
|
+
margin: 0rem;
|
|
68
|
+
border: 1px solid transparent;
|
|
69
|
+
margin-bottom: 0.25rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
p {
|
|
73
|
+
width: 100%;
|
|
74
|
+
color: red;
|
|
75
|
+
font-size: 85%;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
label {
|
|
79
|
+
z-index: 2;
|
|
80
|
+
font-size: 80%;
|
|
199
81
|
position: absolute;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
background-color: var(--row-color-zebra-light);
|
|
204
|
-
color: var(--cell-text-color);
|
|
205
|
-
outline: none;
|
|
206
|
-
width: calc(100% - 4px);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.adate tr {
|
|
210
|
-
height: 1.15rem;
|
|
211
|
-
text-align: center;
|
|
212
|
-
vertical-align: middle;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.adate td {
|
|
216
|
-
border: 2px solid transparent;
|
|
217
|
-
min-width: 2.25ch; /* this doesn't zoom correctly */
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.adate td:hover {
|
|
221
|
-
border: 2px solid var(--focus-cell-outline);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.adate td {
|
|
225
|
-
border: 1px;
|
|
226
|
-
border-style: solid;
|
|
227
|
-
border-color: var(--cell-border-color);
|
|
228
|
-
border-radius: 0px;
|
|
229
|
-
box-sizing: border-box;
|
|
230
|
-
margin: 0px;
|
|
231
|
-
outline: none;
|
|
232
|
-
box-shadow: none;
|
|
233
|
-
color: var(--cell-text-color);
|
|
234
|
-
text-overflow: ellipsis;
|
|
235
|
-
overflow: hidden;
|
|
236
|
-
padding-left: 0.5ch;
|
|
237
|
-
padding-right: 0.5ch;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.adate td:focus,
|
|
241
|
-
.adate td:focus-within {
|
|
242
|
-
background-color: var(--focus-cell-background);
|
|
243
|
-
outline-width: 2px;
|
|
244
|
-
outline-style: solid;
|
|
245
|
-
outline-color: var(--focus-cell-outline);
|
|
246
|
-
box-shadow: none;
|
|
247
|
-
overflow: hidden;
|
|
248
|
-
min-height: 1.15em;
|
|
249
|
-
max-height: 1.15em;
|
|
250
|
-
overflow: hidden;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
button {
|
|
254
|
-
background-color: var(--row-color-zebra-light);
|
|
255
|
-
border: none;
|
|
256
|
-
padding: 0px;
|
|
257
|
-
margin: 0px;
|
|
258
|
-
color: var(--cell-text-color);
|
|
259
|
-
outline: none;
|
|
260
|
-
font-size: var(--table-font-size);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
.dateheader {
|
|
264
|
-
font-weight: 700;
|
|
265
|
-
display: flex;
|
|
266
|
-
align-items: center;
|
|
267
|
-
justify-content: space-between;
|
|
82
|
+
background: white;
|
|
83
|
+
margin: calc(-1.5rem - calc(2.15rem / 2)) 0 0 1ch;
|
|
84
|
+
padding: 0 0.25ch 0 0.25ch;
|
|
268
85
|
}
|
|
269
86
|
|
|
270
|
-
|
|
271
|
-
border
|
|
87
|
+
input:focus {
|
|
88
|
+
border: 1px solid var(--input-active-border-color);
|
|
272
89
|
}
|
|
273
90
|
|
|
274
|
-
|
|
275
|
-
|
|
91
|
+
input:focus + label {
|
|
92
|
+
color: var(--input-active-label-color);
|
|
276
93
|
}
|
|
277
94
|
</style>
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="adatepicker" tabindex="0" ref="adatepicker">
|
|
3
|
+
<table>
|
|
4
|
+
<tr>
|
|
5
|
+
<td @click="previousMonth" :tabindex="-1"><</td>
|
|
6
|
+
<th colspan="5" :tabindex="-1">{{ monthAndYear }}</th>
|
|
7
|
+
<td @click="nextMonth" :tabindex="-1">></td>
|
|
8
|
+
</tr>
|
|
9
|
+
<tr class="days-header">
|
|
10
|
+
<td>M</td>
|
|
11
|
+
<td>T</td>
|
|
12
|
+
<td>W</td>
|
|
13
|
+
<td>T</td>
|
|
14
|
+
<td>F</td>
|
|
15
|
+
<td>S</td>
|
|
16
|
+
<td>S</td>
|
|
17
|
+
</tr>
|
|
18
|
+
<tr v-for="rowNo in numberOfRows" :key="rowNo">
|
|
19
|
+
<td
|
|
20
|
+
v-for="colNo in numberOfColumns"
|
|
21
|
+
:key="getCurrentCell(rowNo, colNo)"
|
|
22
|
+
:contenteditable="false"
|
|
23
|
+
:spellcheck="false"
|
|
24
|
+
:tabindex="0"
|
|
25
|
+
@click.prevent.stop="selectDate(getCurrentCell(rowNo, colNo))"
|
|
26
|
+
@keydown.enter="selectDate(getCurrentCell(rowNo, colNo))"
|
|
27
|
+
:class="{
|
|
28
|
+
todaysDate: isTodaysDate(getCurrentDate(rowNo, colNo)),
|
|
29
|
+
selectedDate: isSelectedDate(getCurrentDate(rowNo, colNo)),
|
|
30
|
+
}">
|
|
31
|
+
{{ new Date(getCurrentDate(rowNo, colNo)).getDate() }}
|
|
32
|
+
</td>
|
|
33
|
+
</tr>
|
|
34
|
+
</table>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
import { defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'
|
|
40
|
+
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
|
41
|
+
|
|
42
|
+
const numberOfRows = 6
|
|
43
|
+
const numberOfColumns = 7
|
|
44
|
+
|
|
45
|
+
const date = defineModel<number | Date>({ default: new Date() })
|
|
46
|
+
const selectedDate = ref(new Date(date.value))
|
|
47
|
+
const currentMonth = ref<number>(selectedDate.value.getMonth())
|
|
48
|
+
const currentYear = ref<number>(selectedDate.value.getFullYear())
|
|
49
|
+
const currentDates = ref<number[]>([])
|
|
50
|
+
const adatepicker = ref<HTMLElement | null>(null)
|
|
51
|
+
|
|
52
|
+
onMounted(async () => {
|
|
53
|
+
populateMonth()
|
|
54
|
+
|
|
55
|
+
// required to allow the elements to be focused in the next step
|
|
56
|
+
await nextTick()
|
|
57
|
+
|
|
58
|
+
const $selectedDate = document.getElementsByClassName('selectedDate')
|
|
59
|
+
if ($selectedDate.length > 0) {
|
|
60
|
+
;($selectedDate[0] as HTMLElement).focus()
|
|
61
|
+
} else {
|
|
62
|
+
const $todaysDate = document.getElementsByClassName('todaysDate')
|
|
63
|
+
if ($todaysDate.length > 0) {
|
|
64
|
+
;($todaysDate[0] as HTMLElement).focus()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const populateMonth = () => {
|
|
70
|
+
currentDates.value = []
|
|
71
|
+
const firstOfMonth = new Date(currentYear.value, currentMonth.value, 1)
|
|
72
|
+
const monthStartWeekday = firstOfMonth.getDay()
|
|
73
|
+
const calendarStartDay = firstOfMonth.setDate(firstOfMonth.getDate() - monthStartWeekday)
|
|
74
|
+
|
|
75
|
+
// assume midnight for all dates while building the calendar
|
|
76
|
+
for (const dayIndex of Array(43).keys()) {
|
|
77
|
+
currentDates.value.push(calendarStartDay + dayIndex * 86400000)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
watch([currentMonth, currentYear], populateMonth)
|
|
82
|
+
const previousYear = () => (currentYear.value -= 1)
|
|
83
|
+
const nextYear = () => (currentYear.value += 1)
|
|
84
|
+
|
|
85
|
+
const previousMonth = () => {
|
|
86
|
+
if (currentMonth.value == 0) {
|
|
87
|
+
currentMonth.value = 11
|
|
88
|
+
previousYear()
|
|
89
|
+
} else {
|
|
90
|
+
currentMonth.value -= 1
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const nextMonth = () => {
|
|
95
|
+
if (currentMonth.value == 11) {
|
|
96
|
+
currentMonth.value = 0
|
|
97
|
+
nextYear()
|
|
98
|
+
} else {
|
|
99
|
+
currentMonth.value += 1
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const isTodaysDate = (day: string | number | Date) => {
|
|
104
|
+
const todaysDate = new Date()
|
|
105
|
+
if (currentMonth.value !== todaysDate.getMonth()) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
return todaysDate.toDateString() === new Date(day).toDateString()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const isSelectedDate = (day: string | number | Date) => {
|
|
112
|
+
return new Date(day).toDateString() === new Date(selectedDate.value).toDateString()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const getCurrentCell = (rowNo: number, colNo: number) => {
|
|
116
|
+
return (rowNo - 1) * numberOfColumns + colNo
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const getCurrentDate = (rowNo: number, colNo: number) => {
|
|
120
|
+
return currentDates.value[getCurrentCell(rowNo, colNo)]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const selectDate = (currentIndex: number) => {
|
|
124
|
+
date.value = selectedDate.value = new Date(currentDates.value[currentIndex])
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const monthAndYear = computed(() => {
|
|
128
|
+
return new Date(currentYear.value, currentMonth.value, 1).toLocaleDateString(undefined, {
|
|
129
|
+
year: 'numeric',
|
|
130
|
+
month: 'long',
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// setup keyboard navigation
|
|
135
|
+
useKeyboardNav([
|
|
136
|
+
{
|
|
137
|
+
parent: adatepicker,
|
|
138
|
+
selectors: 'td',
|
|
139
|
+
handlers: {
|
|
140
|
+
...defaultKeypressHandlers,
|
|
141
|
+
...{
|
|
142
|
+
'keydown.pageup': previousMonth,
|
|
143
|
+
'keydown.shift.pageup': previousYear,
|
|
144
|
+
'keydown.pagedown': nextMonth,
|
|
145
|
+
'keydown.shift.pagedown': nextYear,
|
|
146
|
+
// TODO: this is a hack to override the stonecrop enter handler;
|
|
147
|
+
// store context inside the component so that handlers can be setup consistently
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
149
|
+
'keydown.enter': () => {}, // select this date
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
])
|
|
154
|
+
</script>
|
|
155
|
+
|
|
156
|
+
<style>
|
|
157
|
+
@import url('@stonecrop/themes/default/default.css');
|
|
158
|
+
@import url('@/theme/adate.css');
|
|
159
|
+
@import url('@/theme/aform.css');
|
|
160
|
+
</style>
|
package/src/histoire.setup.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defineSetupVue3 } from '@histoire/plugin-vue'
|
|
2
2
|
|
|
3
3
|
import ACheckbox from '@/components/form/ACheckbox.vue'
|
|
4
|
+
import ADate from '@/components/form/ADate.vue'
|
|
5
|
+
import ADatePicker from '@/components/form/ADatePicker.vue'
|
|
4
6
|
import AFieldset from '@/components/form/AFieldset.vue'
|
|
5
7
|
import AForm from '@/components/AForm.vue'
|
|
6
8
|
import ANumericInput from '@/components/form/ANumericInput.vue'
|
|
@@ -12,6 +14,8 @@ import '@stonecrop/atable/styles'
|
|
|
12
14
|
export const setupVue3 = defineSetupVue3(({ app }) => {
|
|
13
15
|
// TODO: (typing) add typing for ATable components
|
|
14
16
|
app.component('ACheckbox', ACheckbox)
|
|
17
|
+
app.component('ADate', ADate)
|
|
18
|
+
app.component('ADatePicker', ADatePicker)
|
|
15
19
|
app.component('AFieldset', AFieldset)
|
|
16
20
|
app.component('AForm', AForm)
|
|
17
21
|
app.component('ANumericInput', ANumericInput)
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import ACheckbox from '@/components/form/ACheckbox.vue'
|
|
|
4
4
|
import AComboBox from '@/components/form/AComboBox.vue'
|
|
5
5
|
import ADate from '@/components/form/ADate.vue'
|
|
6
6
|
import ADropdown from '@/components/form/ADropdown.vue'
|
|
7
|
+
import ADatePicker from '@/components/form/ADatePicker.vue'
|
|
7
8
|
import AFieldset from '@/components/form/AFieldset.vue'
|
|
8
9
|
import AForm from '@/components/AForm.vue'
|
|
9
10
|
import ANumericInput from '@/components/form/ANumericInput.vue'
|
|
@@ -16,6 +17,7 @@ function install(app: App /* options */) {
|
|
|
16
17
|
app.component('ACombobox', AComboBox)
|
|
17
18
|
app.component('ADate', ADate)
|
|
18
19
|
app.component('ADropdown', ADropdown)
|
|
20
|
+
app.component('ADatePicker', ADatePicker)
|
|
19
21
|
app.component('AFieldset', AFieldset)
|
|
20
22
|
app.component('AForm', AForm)
|
|
21
23
|
app.component('ANumericInput', ANumericInput)
|
|
@@ -24,4 +26,4 @@ function install(app: App /* options */) {
|
|
|
24
26
|
// app.component('AQuantity', AQuantity)
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
export { ACheckbox, AComboBox, ADate, ADropdown, AFieldset, AForm, ANumericInput, ATextInput, install }
|
|
29
|
+
export { ACheckbox, AComboBox, ADate, ADropdown, ADatePicker, AFieldset, AForm, ANumericInput, ATextInput, install }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.adatepicker {
|
|
2
|
+
font-size: var(--table-font-size);
|
|
3
|
+
display: inline-table;
|
|
4
|
+
color: var(--cell-text-color);
|
|
5
|
+
outline: none;
|
|
6
|
+
border-collapse: collapse;
|
|
7
|
+
/* width: calc(100% - 4px); */
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.adatepicker tr {
|
|
11
|
+
height: 1.15rem;
|
|
12
|
+
height: 1.15rem;
|
|
13
|
+
text-align: center;
|
|
14
|
+
vertical-align: middle;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.adatepicker td {
|
|
18
|
+
border: 2px solid transparent;
|
|
19
|
+
outline: 2px solid transparent;
|
|
20
|
+
min-width: 3ch;
|
|
21
|
+
max-width: 3ch;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.adatepicker td:focus,
|
|
25
|
+
.adatepicker td:focus-within {
|
|
26
|
+
outline: 1px dashed black;
|
|
27
|
+
box-shadow: none;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
min-height: 1.15em;
|
|
30
|
+
max-height: 1.15em;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
}
|
|
33
|
+
.adatepicker .selectedDate {
|
|
34
|
+
outline: 1px solid black;
|
|
35
|
+
background: var(--gray-20);
|
|
36
|
+
font-weight: bolder;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.adatepicker .todaysDate {
|
|
40
|
+
font-weight: bolder;
|
|
41
|
+
text-decoration: underline;
|
|
42
|
+
color: black;
|
|
43
|
+
}
|
|
44
|
+
.days-header > td {
|
|
45
|
+
font-weight: bold;
|
|
46
|
+
}
|
|
47
|
+
.prev-date {
|
|
48
|
+
color: var(--gray-20);
|
|
49
|
+
}
|