@7365admin1/layer-common 3.2.2-staging.146 → 3.2.2-staging.148
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/components/BtnUploadFile.vue +53 -11
- package/components/Input/DatePicker.vue +1 -1
- package/components/Input/DateTimePicker.vue +1 -0
- package/components/Input/FileV2.vue +39 -6
- package/components/Input/InputPhoneNumberV2.vue +2 -1
- package/components/Input/NRICNumber.vue +1 -0
- package/components/Input/NewDate.vue +1 -0
- package/components/Input/Number.vue +1 -0
- package/components/Input/Password.vue +1 -0
- package/components/Input/VehicleNumber.vue +1 -0
- package/components/SwitchContext.vue +15 -3
- package/package.json +1 -1
|
@@ -10,12 +10,17 @@
|
|
|
10
10
|
<v-row no-gutters>
|
|
11
11
|
<v-col v-if="value || readOnly" cols="12">
|
|
12
12
|
<v-row no-gutters>
|
|
13
|
+
<!-- The strip is one control split in two: the file name, and the
|
|
14
|
+
cross that clears it. `rounded=""` on the read-only card was
|
|
15
|
+
not "no radius" - Vuetify's `useRounded` treats an empty string
|
|
16
|
+
as `true` and adds `.rounded`, i.e. its own 4px. The design's
|
|
17
|
+
radius is stated here instead, on both ends. -->
|
|
13
18
|
<v-card
|
|
14
19
|
variant="outlined"
|
|
15
20
|
border="thin"
|
|
16
|
-
class="
|
|
17
|
-
:
|
|
18
|
-
height="
|
|
21
|
+
class="btn-input-file__name"
|
|
22
|
+
:class="{ 'btn-input-file__name--solo': readOnly }"
|
|
23
|
+
height="40"
|
|
19
24
|
@click="emit('click:view')"
|
|
20
25
|
>
|
|
21
26
|
<v-row no-gutters class="fill-height" align="center">
|
|
@@ -26,24 +31,28 @@
|
|
|
26
31
|
v-if="!readOnly"
|
|
27
32
|
variant="outlined"
|
|
28
33
|
border="s-0 thin"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
height="36"
|
|
34
|
+
class="btn-input-file__clear"
|
|
35
|
+
height="40"
|
|
32
36
|
@click="emit('click:close')"
|
|
33
37
|
>
|
|
34
38
|
<v-row no-gutters class="fill-height" align="center">
|
|
35
|
-
<v-icon size="
|
|
39
|
+
<v-icon size="18"> mdi-close </v-icon>
|
|
36
40
|
</v-row>
|
|
37
41
|
</v-card>
|
|
38
42
|
</v-row>
|
|
39
43
|
</v-col>
|
|
40
44
|
|
|
41
45
|
<v-col v-else cols="12">
|
|
46
|
+
<!-- This arm is the `v-else` of `v-if="value || readOnly"`, so
|
|
47
|
+
`value` is always falsy by the time it renders: the old
|
|
48
|
+
`:prepend-icon="value ? '' : ..."` had an arm that could never be
|
|
49
|
+
taken, and the icon is unconditional. `screen-btn-ghost` is the
|
|
50
|
+
design's 40px bordered button while keeping Vuetify's `loading`
|
|
51
|
+
spinner, which the upload needs and `AppButton` does not have. -->
|
|
42
52
|
<v-btn
|
|
43
|
-
variant="
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
:prepend-icon="value ? '' : 'mdi-tray-arrow-up'"
|
|
53
|
+
variant="flat"
|
|
54
|
+
class="text-none screen-btn-ghost"
|
|
55
|
+
prepend-icon="mdi-tray-arrow-up"
|
|
47
56
|
:disabled="loading"
|
|
48
57
|
:loading="loading"
|
|
49
58
|
@click="selectAttachment"
|
|
@@ -137,3 +146,36 @@ const errorMessage = computed(() => {
|
|
|
137
146
|
return null;
|
|
138
147
|
});
|
|
139
148
|
</script>
|
|
149
|
+
|
|
150
|
+
<style scoped>
|
|
151
|
+
/* The design's control box on the attachment strip: 40px, `--r-inner` on the
|
|
152
|
+
outer corners only (the two cards butt together), a `--line` edge and the
|
|
153
|
+
13.5px/500 cell type - not Vuetify's `text-caption` scale and 4px radius.
|
|
154
|
+
`:deep` because the box being styled is the `v-card` root Vuetify renders. */
|
|
155
|
+
.btn-input-file__name,
|
|
156
|
+
.btn-input-file__clear {
|
|
157
|
+
font-family: var(--font-sans);
|
|
158
|
+
font-size: var(--fs-cell);
|
|
159
|
+
font-weight: var(--fw-cell);
|
|
160
|
+
color: var(--text2);
|
|
161
|
+
border-color: var(--border);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.btn-input-file__name {
|
|
165
|
+
padding-inline: 14px;
|
|
166
|
+
border-start-start-radius: var(--r-inner);
|
|
167
|
+
border-end-start-radius: var(--r-inner);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Read-only: there is no cross beside it, so it is a single rounded box. */
|
|
171
|
+
.btn-input-file__name--solo {
|
|
172
|
+
border-radius: var(--r-inner);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.btn-input-file__clear {
|
|
176
|
+
display: inline;
|
|
177
|
+
padding-inline: 12px;
|
|
178
|
+
border-start-end-radius: var(--r-inner);
|
|
179
|
+
border-end-end-radius: var(--r-inner);
|
|
180
|
+
}
|
|
181
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="d-flex flex-column">
|
|
3
|
-
<v-text-field v-bind="$attrs" ref="datePickerRef" :model-value="dateFormattedReadOnly" autocomplete="off"
|
|
3
|
+
<v-text-field v-bind="$attrs" class="filter-field" ref="datePickerRef" :model-value="dateFormattedReadOnly" autocomplete="off"
|
|
4
4
|
:placeholder="placeholder" :rules="rules" style="z-index: 10" @click="openDatePicker" @click:clear.stop="clearDate">
|
|
5
5
|
<template #append-inner>
|
|
6
6
|
<v-icon icon="mdi-calendar" @click.stop="openDatePicker" />
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<template v-else>
|
|
23
23
|
<v-file-upload v-model="uploadFiles" density="compact" @update:model-value="handleUpdateValue"
|
|
24
24
|
:loading="processing" :disabled="processing" :height="height" :title="title" :accept="accept"
|
|
25
|
-
:name="`upload_images`" class="
|
|
25
|
+
:name="`upload_images`" class="w-100 file-v2__drop" clearable :multiple="multiple">
|
|
26
26
|
<template #item="{ props: itemProps, file }">
|
|
27
27
|
<v-file-upload-item v-bind="itemProps" lines="one" nav @click="handleClickItem(file)">
|
|
28
28
|
<template #prepend>
|
|
@@ -30,8 +30,19 @@
|
|
|
30
30
|
</template>
|
|
31
31
|
|
|
32
32
|
<!-- delete button NOT shown in view mode -->
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
<!-- This button had NO icon and NO label, so it drew as an empty
|
|
34
|
+
slab, and `color="primary"` filled that slab with the design's
|
|
35
|
+
FOREGROUND token (the link ink) rather than a fill. It is the
|
|
36
|
+
remove control for one attached file: a plain close glyph. -->
|
|
37
|
+
<template #clear>
|
|
38
|
+
<v-btn
|
|
39
|
+
v-if="!viewMode"
|
|
40
|
+
icon="mdi-close"
|
|
41
|
+
variant="text"
|
|
42
|
+
size="small"
|
|
43
|
+
aria-label="Remove file"
|
|
44
|
+
@click.stop="handleRemove(file)"
|
|
45
|
+
/>
|
|
35
46
|
</template>
|
|
36
47
|
</v-file-upload-item>
|
|
37
48
|
</template>
|
|
@@ -39,7 +50,7 @@
|
|
|
39
50
|
</template>
|
|
40
51
|
|
|
41
52
|
<v-row no-gutters class="w-100" v-if="errorMessage">
|
|
42
|
-
<p class="text-error w-100 text-center
|
|
53
|
+
<p class="text-error w-100 text-center file-v2__error">{{ errorMessage }}</p>
|
|
43
54
|
</v-row>
|
|
44
55
|
|
|
45
56
|
<ImageCarousel v-model="showImageCarousel" :files="idsArray" :active-file-id="activeImageId" />
|
|
@@ -224,12 +235,34 @@ async function downloadFile(id: string, filename: string) {
|
|
|
224
235
|
|
|
225
236
|
|
|
226
237
|
<style scoped>
|
|
238
|
+
/* The drop zone on the design's surface: `--r-inner`, a `--border` edge and the
|
|
239
|
+
13.5px cell type, instead of Vuetify's 4px radius and `text-caption` scale.
|
|
240
|
+
`:deep` because every box below is rendered by `v-file-upload`. */
|
|
241
|
+
.file-v2__drop {
|
|
242
|
+
font-family: var(--font-sans);
|
|
243
|
+
font-size: var(--fs-cell);
|
|
244
|
+
border-radius: var(--r-inner);
|
|
245
|
+
border-color: var(--border);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.file-v2__drop :deep(.v-file-upload-item) {
|
|
249
|
+
border-radius: var(--r-inner);
|
|
250
|
+
}
|
|
251
|
+
|
|
227
252
|
* :deep(.v-file-upload-title) {
|
|
228
|
-
font-
|
|
229
|
-
font-
|
|
253
|
+
font-family: var(--font-sans);
|
|
254
|
+
font-size: var(--fs-card-title);
|
|
255
|
+
font-weight: var(--fw-card-title);
|
|
256
|
+
color: var(--text);
|
|
230
257
|
}
|
|
231
258
|
|
|
232
259
|
* :deep(.v-file-upload-items) {
|
|
233
260
|
min-width: 100%;
|
|
234
261
|
}
|
|
262
|
+
|
|
263
|
+
.file-v2__error {
|
|
264
|
+
font-family: var(--font-sans);
|
|
265
|
+
font-size: var(--fs-cell);
|
|
266
|
+
font-weight: var(--fw-cell);
|
|
267
|
+
}
|
|
235
268
|
</style>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
item-title="dial_code"
|
|
9
9
|
item-value="code"
|
|
10
10
|
hide-details
|
|
11
|
-
class="px-0"
|
|
11
|
+
class="px-0 filter-field"
|
|
12
12
|
:density="density"
|
|
13
13
|
style="max-width: 110px"
|
|
14
14
|
:rules="[...props.rules]"
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
<v-mask-input
|
|
33
33
|
v-model="input"
|
|
34
|
+
class="filter-field"
|
|
34
35
|
:mask="currentMask"
|
|
35
36
|
:rules="[...props.rules, validatePhone]"
|
|
36
37
|
ref="maskRef"
|
|
@@ -201,9 +201,21 @@ const selectItem = (value: string) => {
|
|
|
201
201
|
color: var(--text);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
/* The panel is a `v-card`, and Vuetify puts it inside `.v-overlay__content`.
|
|
205
|
+
`screens.css` gives EVERY card in an overlay the modal shape - 16px and the
|
|
206
|
+
modal shadow - with `!important`, because dialogs open from sixty components
|
|
207
|
+
and the shape had to be stated once. A menu is an overlay too, so the panel
|
|
208
|
+
was silently taking the modal shape: measured 16px and
|
|
209
|
+
`rgba(10, 12, 16, 0.3) 0 24px 64px`, not the 14px `--r-menu` and the lighter
|
|
210
|
+
`--shadow-menu` it asks for.
|
|
211
|
+
`!important` alone does NOT win it back: `.switch-context__panel[data-v-...]`
|
|
212
|
+
and `.v-overlay__content > .v-card` are both two classes, the scope attribute
|
|
213
|
+
counts, and a tie goes to whichever sheet loaded last - which is screens.css.
|
|
214
|
+
Measured still 16px with `!important` on the plain class. So the selector
|
|
215
|
+
carries the overlay class too, to out-specify rather than tie. */
|
|
216
|
+
.v-overlay__content > .switch-context__panel {
|
|
217
|
+
border-radius: var(--r-menu) !important;
|
|
218
|
+
box-shadow: var(--shadow-menu) !important;
|
|
207
219
|
border: 1px solid var(--border);
|
|
208
220
|
background: var(--card);
|
|
209
221
|
padding: 14px;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "3.2.2-staging.
|
|
5
|
+
"version": "3.2.2-staging.148",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|