create-nexwire 4.2.4 → 4.2.5

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.
Files changed (35) hide show
  1. package/express/.vscode/extensions.json +6 -0
  2. package/express/.vscode/settings.json +37 -26
  3. package/express/biome.json +99 -66
  4. package/express/package.json +30 -28
  5. package/express/src/database/schema.ts +2 -2
  6. package/express/src/resources/src/components/Checkbox.vue +32 -29
  7. package/express/src/resources/src/components/Input.vue +243 -223
  8. package/express/src/resources/src/components/InputGroup.vue +147 -145
  9. package/express/src/resources/src/components/InputPasswordToggle.vue +229 -213
  10. package/express/src/resources/src/components/Modal.vue +71 -55
  11. package/express/src/resources/src/components/Refresh.vue +19 -0
  12. package/express/src/resources/src/helpers/assets.ts +51 -0
  13. package/express/src/resources/src/main.ts +3 -1
  14. package/express/src/resources/src/plugins/gum.ts +1 -1
  15. package/express/src/resources/src/stores/auth.ts +184 -164
  16. package/express/src/resources/vite.config.ts +9 -2
  17. package/express/src/storage/database/nexwire.sqlite +0 -0
  18. package/hono/.vscode/extensions.json +6 -0
  19. package/hono/.vscode/settings.json +37 -26
  20. package/hono/biome.json +25 -2
  21. package/hono/package.json +24 -22
  22. package/hono/src/database/schema.ts +2 -2
  23. package/hono/src/resources/src/components/Checkbox.vue +32 -29
  24. package/hono/src/resources/src/components/Input.vue +243 -234
  25. package/hono/src/resources/src/components/InputGroup.vue +147 -149
  26. package/hono/src/resources/src/components/InputPasswordToggle.vue +229 -222
  27. package/hono/src/resources/src/components/Modal.vue +71 -55
  28. package/hono/src/resources/src/components/Refresh.vue +19 -0
  29. package/hono/src/resources/src/helpers/assets.ts +51 -0
  30. package/hono/src/resources/src/main.ts +3 -1
  31. package/hono/src/resources/src/plugins/gum.ts +1 -1
  32. package/hono/src/resources/src/stores/auth.ts +184 -164
  33. package/hono/src/resources/vite.config.ts +9 -2
  34. package/hono/src/storage/database/nexwire.sqlite +0 -0
  35. package/package.json +1 -1
@@ -1,234 +1,243 @@
1
- <template>
2
- <div :class="topclass">
3
- <div class="position-relative">
4
- <label
5
- :for="inputId"
6
- class="d-flex align-items-center mb-1"
7
- :class="{ 'd-none': !inputLabel }">
8
- <div class="position-relative">
9
- <span class="text-capitalize" v-html="inputLabel"></span>
10
- <span
11
- class="position-absolute text-danger rounded-circle bg-danger must"
12
- :class="{ 'd-none': !props.must }"></span>
13
- </div>
14
- <div
15
- class="text-end ms-auto text-primary fw-semibold"
16
- :class="{ 'd-none': !props.hood }"
17
- style="font-size: 12px; margin-top: 0.15rem"
18
- v-html="hoodHtml"></div>
19
- </label>
20
- <input
21
- ref="inputRef"
22
- class="form-control"
23
- :value="props.modelValue"
24
- :maxlength="maxLengthAttr"
25
- :readonly="props.readonly"
26
- v-bind="$attrs"
27
- :autocomplete="inputAutocomplete"
28
- @input="updateModel" />
29
- <div
30
- class="position-absolute bottom-0 end-0 pe-1 text-secondary max"
31
- :class="{ 'd-none': !max }">
32
- {{ maxCounter }}
33
- </div>
34
- </div>
35
- <div
36
- :id="`${inputId}Help`"
37
- class="form-text mt-1 text-danger"
38
- :class="{ 'd-none': !props.err }">
39
- {{ props.err }}
40
- </div>
41
- </div>
42
- </template>
43
-
44
- <script setup lang="ts">
45
- import { computed, nextTick, onMounted, ref, useAttrs } from "vue";
46
- import { browserDetect } from "@/plugins/browserDetect";
47
-
48
- const { isFirefox } = browserDetect;
49
-
50
- const $attrs = useAttrs();
51
- const inputRef = ref<HTMLInputElement | null>(null);
52
- type InputCategory =
53
- | "number"
54
- | "decimal"
55
- | "+decimal-"
56
- | "mobile"
57
- | "tax-period"
58
- | "bin"
59
- | "challan-number"
60
- | string;
61
-
62
- interface InputProps {
63
- focus?: boolean;
64
- must?: boolean;
65
- err?: string | boolean;
66
- modelValue?: string | number;
67
- category?: InputCategory;
68
- hood?: string | boolean | number;
69
- readonly?: boolean;
70
- }
71
-
72
- const props = withDefaults(defineProps<InputProps>(), {
73
- err: false,
74
- modelValue: ""
75
- });
76
-
77
- const topclass = computed(() => ($attrs.topclass as string | undefined) || "mb-2");
78
- const inputId = computed(() => ($attrs.id as string | undefined) || "");
79
- const inputLabel = computed(() => ($attrs.label as string | undefined) || "");
80
- const inputType = computed(() => ($attrs.type as string | undefined) || "text");
81
-
82
- const max = computed<number | null>(() => {
83
- const raw = $attrs.maxlength as string | number | undefined;
84
- return raw != null ? Number(raw) : null;
85
- });
86
-
87
- const inputAutocomplete = computed(() => {
88
- const attrAutocomplete = $attrs.autocomplete as string | undefined;
89
- if (attrAutocomplete) {
90
- return attrAutocomplete;
91
- }
92
- return ["number", "decimal"].includes(props.category ?? "") ? "off" : "on";
93
- });
94
-
95
- const maxLengthAttr = computed<number | undefined>(() => max.value ?? undefined);
96
-
97
- const hoodHtml = computed(() =>
98
- props.hood === false || props.hood == null ? "" : String(props.hood)
99
- );
100
-
101
- const maxCounter = computed(() => {
102
- if (max.value == null) {
103
- return "";
104
- }
105
-
106
- if (!isFirefox && inputType.value === "month") {
107
- return "";
108
- }
109
-
110
- return max.value - String(props.modelValue).length;
111
- });
112
-
113
- const emit = defineEmits<(event: "update:modelValue", value: string | number) => void>();
114
- const updateModel = (e: Event) => {
115
- const target = e.target as HTMLInputElement;
116
-
117
- if (props.category === "number") {
118
- emit("update:modelValue", (target.value = target.value.replace(/[^\d]/gi, "")));
119
- } else if (props.category === "decimal") {
120
- let val = target.value;
121
-
122
- // Remove everything except digits, decimal point, and minus sign
123
- val = val.replace(/[^0-9.]/g, "");
124
-
125
- // Allow only one decimal point
126
- const parts = val.split(".");
127
- if (parts.length > 2) {
128
- val = `${parts[0]}.${parts.slice(1).join("")}`;
129
- }
130
-
131
- emit("update:modelValue", (target.value = val));
132
- } else if (props.category === "+decimal-") {
133
- let val = target.value;
134
-
135
- // Remove everything except digits, decimal point, and minus sign
136
- val = val.replace(/[^0-9.-]/g, ""); // if need minus sign
137
-
138
- // Move minus sign to the front if it exists anywhere
139
- const isNegative = val.includes("-");
140
- val = val.replace(/-/g, ""); // remove all minus signs
141
- if (isNegative) {
142
- val = `-${val}`;
143
- }
144
-
145
- // Allow only one decimal point
146
- const parts = val.split(".");
147
- if (parts.length > 2) {
148
- val = `${parts[0]}.${parts.slice(1).join("")}`;
149
- }
150
-
151
- emit("update:modelValue", (target.value = val));
152
- } else if (props.category === "mobile") {
153
- let digits = target.value.replace(/[^\d]/g, ""); // only digits
154
- let val = digits;
155
- if (target.value.includes("+")) {
156
- val = `+${digits}`;
157
- }
158
- emit("update:modelValue", (target.value = val));
159
- } else if (props.category === "tax-period") {
160
- let val = target.value.replace(/[^\d-]/g, ""); // Only numbers and hyphen
161
- val = val.replace(/-/g, ""); // Remove all hyphens
162
- val = val.slice(0, 6); // Only 6 digits (YYYYMM)
163
-
164
- if (val.length > 4) {
165
- let year = val.slice(0, 4);
166
- let month = val.slice(4, 6);
167
-
168
- // Only correct if both month digits entered
169
- if (month.length === 2) {
170
- let m = parseInt(month, 10);
171
- // Clamp month between 1 and 12
172
- if (m < 1) m = 1;
173
- if (m > 12) m = 12;
174
- // Always pad to 2 digits
175
- month = m.toString().padStart(2, "0");
176
- }
177
-
178
- val = `${year}-${month}`;
179
- }
180
-
181
- emit("update:modelValue", (target.value = val));
182
- } else if (props.category === "bin") {
183
- let digits = target.value.replace(/[^\d]/g, "");
184
- digits = digits.slice(0, 14);
185
- let formatted = digits;
186
- if (digits.length > 9) {
187
- formatted = `${digits.slice(0, 9)}-${digits.slice(9, 14)}`;
188
- }
189
- emit("update:modelValue", (target.value = formatted));
190
- } else if (props.category === 'echallan-number') {
191
- // Format: V + 9 digits (V000517226)
192
- let raw = (target.value || '').toUpperCase();
193
-
194
- // keep only digits, but allow V (we’ll force V at start)
195
- let digits = raw.replace(/[^\d]/g, '').slice(0, 9);
196
-
197
- // always prefix V
198
- let formatted = 'V' + digits;
199
-
200
- emit('update:modelValue', (target.value = formatted));
201
-
202
- } else if (props.category === "challan-number") {
203
- let digits = target.value.replace(/[^\d]/g, "");
204
- digits = digits.slice(0, 16);
205
- let formatted = digits;
206
- if (digits.length > 4) {
207
- formatted = `${digits.slice(0, 4)}-${digits.slice(4, 16)}`;
208
- }
209
- emit("update:modelValue", (target.value = formatted));
210
- } else {
211
- emit("update:modelValue", target.value);
212
- }
213
- };
214
-
215
- onMounted(() => {
216
- const shouldFocus = props.focus !== false && props.focus !== undefined;
217
- if (!shouldFocus) return;
218
-
219
- nextTick(() => inputRef.value?.focus());
220
- });
221
- </script>
222
-
223
- <style lang="scss" scoped>
224
- .must {
225
- width: 4px;
226
- height: 4px;
227
- margin-left: 2px;
228
- margin-top: 5px;
229
- }
230
-
231
- .max {
232
- font-size: 0.6rem;
233
- }
234
- </style>
1
+ <template>
2
+ <div :class="topclass">
3
+ <div class="position-relative">
4
+ <label
5
+ :for="inputId"
6
+ class="d-flex align-items-center mb-1"
7
+ :class="{ 'd-none': !inputLabel }"
8
+ >
9
+ <div class="position-relative">
10
+ <span class="text-capitalize" v-html="inputLabel"></span>
11
+ <span
12
+ class="position-absolute text-danger rounded-circle bg-danger must"
13
+ :class="{ 'd-none': !props.must }"
14
+ ></span>
15
+ </div>
16
+ <div
17
+ class="text-end ms-auto text-primary fw-semibold"
18
+ :class="{ 'd-none': !props.hood }"
19
+ style="font-size: 12px; margin-top: 0.15rem"
20
+ v-html="hoodHtml"
21
+ ></div>
22
+ </label>
23
+ <input
24
+ ref="inputRef"
25
+ class="form-control shadow-none"
26
+ :value="props.modelValue"
27
+ :maxlength="maxLengthAttr"
28
+ :readonly="props.readonly"
29
+ v-bind="$attrs"
30
+ :autocomplete="inputAutocomplete"
31
+ @input="updateModel"
32
+ />
33
+ <div
34
+ class="position-absolute bottom-0 end-0 pe-1 text-secondary max"
35
+ :class="{ 'd-none': !max }"
36
+ >
37
+ {{ maxCounter }}
38
+ </div>
39
+ </div>
40
+ <div
41
+ :id="`${inputId}Help`"
42
+ class="form-text mt-1 text-danger"
43
+ :class="{ 'd-none': !props.err }"
44
+ >
45
+ {{ props.err }}
46
+ </div>
47
+ </div>
48
+ </template>
49
+
50
+ <script setup lang="ts">
51
+ import { computed, nextTick, onMounted, ref, useAttrs } from "vue";
52
+ import { browserDetect } from "@/plugins/browserDetect";
53
+
54
+ defineOptions({ name: "Input", inheritAttrs: false });
55
+
56
+ const { isFirefox } = browserDetect;
57
+
58
+ const $attrs = useAttrs();
59
+ const inputRef = ref<HTMLInputElement | null>(null);
60
+ type InputCategory =
61
+ | "number"
62
+ | "decimal"
63
+ | "+decimal-"
64
+ | "mobile"
65
+ | "tax-period"
66
+ | "bin"
67
+ | "challan-number"
68
+ | string;
69
+
70
+ interface InputProps {
71
+ focus?: boolean;
72
+ must?: boolean;
73
+ err?: string | boolean;
74
+ modelValue?: string | number;
75
+ category?: InputCategory;
76
+ hood?: string | boolean | number;
77
+ readonly?: boolean;
78
+ }
79
+
80
+ const props = withDefaults(defineProps<InputProps>(), {
81
+ err: false,
82
+ modelValue: "",
83
+ });
84
+
85
+ const topclass = computed(() => ($attrs.topclass as string | undefined) || "mb-2");
86
+ const inputId = computed(() => ($attrs.id as string | undefined) || "");
87
+ const inputLabel = computed(() => ($attrs.label as string | undefined) || "");
88
+ const inputType = computed(() => ($attrs.type as string | undefined) || "text");
89
+
90
+ const max = computed<number | null>(() => {
91
+ const raw = $attrs.maxlength as string | number | undefined;
92
+ return raw != null ? Number(raw) : null;
93
+ });
94
+
95
+ const inputAutocomplete = computed(() => {
96
+ const attrAutocomplete = $attrs.autocomplete as string | undefined;
97
+ if (attrAutocomplete) {
98
+ return attrAutocomplete;
99
+ }
100
+ return ["number", "decimal"].includes(props.category ?? "") ? "off" : "on";
101
+ });
102
+
103
+ const maxLengthAttr = computed<number | undefined>(() => max.value ?? undefined);
104
+
105
+ const hoodHtml = computed(() =>
106
+ props.hood === false || props.hood == null ? "" : String(props.hood),
107
+ );
108
+
109
+ const maxCounter = computed(() => {
110
+ if (max.value == null) {
111
+ return "";
112
+ }
113
+
114
+ if (!isFirefox && inputType.value === "month") {
115
+ return "";
116
+ }
117
+
118
+ return max.value - String(props.modelValue).length;
119
+ });
120
+
121
+ const emit = defineEmits<(event: "update:modelValue", value: string | number) => void>();
122
+ const updateModel = (e: Event) => {
123
+ const target = e.target as HTMLInputElement;
124
+
125
+ if (props.category === "number") {
126
+ emit("update:modelValue", (target.value = target.value.replace(/[^\d]/gi, "")));
127
+ } else if (props.category === "decimal") {
128
+ let val = target.value;
129
+
130
+ // Remove everything except digits, decimal point, and minus sign
131
+ val = val.replace(/[^0-9.]/g, "");
132
+
133
+ // Allow only one decimal point
134
+ const parts = val.split(".");
135
+ if (parts.length > 2) {
136
+ val = `${parts[0]}.${parts.slice(1).join("")}`;
137
+ }
138
+
139
+ emit("update:modelValue", (target.value = val));
140
+ } else if (props.category === "+decimal-") {
141
+ let val = target.value;
142
+
143
+ // Remove everything except digits, decimal point, and minus sign
144
+ val = val.replace(/[^0-9.-]/g, ""); // if need minus sign
145
+
146
+ // Move minus sign to the front if it exists anywhere
147
+ const isNegative = val.includes("-");
148
+ val = val.replace(/-/g, ""); // remove all minus signs
149
+ if (isNegative) {
150
+ val = `-${val}`;
151
+ }
152
+
153
+ // Allow only one decimal point
154
+ const parts = val.split(".");
155
+ if (parts.length > 2) {
156
+ val = `${parts[0]}.${parts.slice(1).join("")}`;
157
+ }
158
+
159
+ emit("update:modelValue", (target.value = val));
160
+ } else if (props.category === "mobile") {
161
+ let digits = target.value.replace(/[^\d]/g, ""); // only digits
162
+ let val = digits;
163
+ if (target.value.includes("+")) {
164
+ val = `+${digits}`;
165
+ }
166
+ emit("update:modelValue", (target.value = val));
167
+ } else if (props.category === "tax-period") {
168
+ let val = target.value.replace(/[^\d-]/g, ""); // Only numbers and hyphen
169
+ val = val.replace(/-/g, ""); // Remove all hyphens
170
+ val = val.slice(0, 6); // Only 6 digits (YYYYMM)
171
+
172
+ if (val.length > 4) {
173
+ let year = val.slice(0, 4);
174
+ let month = val.slice(4, 6);
175
+
176
+ // Only correct if both month digits entered
177
+ if (month.length === 2) {
178
+ let m = parseInt(month, 10);
179
+ // Clamp month between 1 and 12
180
+ if (m < 1) m = 1;
181
+ if (m > 12) m = 12;
182
+ // Always pad to 2 digits
183
+ month = m.toString().padStart(2, "0");
184
+ }
185
+
186
+ val = `${year}-${month}`;
187
+ }
188
+
189
+ emit("update:modelValue", (target.value = val));
190
+ } else if (props.category === "bin") {
191
+ let digits = target.value.replace(/[^\d]/g, "");
192
+ digits = digits.slice(0, 14);
193
+ let formatted = digits;
194
+ if (digits.length > 9) {
195
+ formatted = `${digits.slice(0, 9)}-${digits.slice(9, 14)}`;
196
+ }
197
+ emit("update:modelValue", (target.value = formatted));
198
+ } else if (props.category === "echallan-number") {
199
+ // Format: V + 9 digits (V000517226)
200
+ let raw = (target.value || "").toUpperCase();
201
+
202
+ // keep only digits, but allow V (we’ll force V at start)
203
+ let digits = raw.replace(/[^\d]/g, "").slice(0, 9);
204
+
205
+ // always prefix V
206
+ let formatted = `V${digits}`;
207
+
208
+ emit("update:modelValue", (target.value = formatted));
209
+ } else if (props.category === "challan-number") {
210
+ let digits = target.value.replace(/[^\d]/g, "");
211
+ digits = digits.slice(0, 16);
212
+ let formatted = digits;
213
+ if (digits.length > 4) {
214
+ formatted = `${digits.slice(0, 4)}-${digits.slice(4, 16)}`;
215
+ }
216
+ emit("update:modelValue", (target.value = formatted));
217
+ } else {
218
+ emit("update:modelValue", target.value);
219
+ }
220
+ };
221
+
222
+ onMounted(async () => {
223
+ const shouldFocus = props.focus !== false && props.focus !== undefined;
224
+ if (!shouldFocus) return;
225
+
226
+ await nextTick();
227
+ // preventScroll: focusing inside a modal must not scroll the modal/page
228
+ inputRef.value?.focus({ preventScroll: true });
229
+ });
230
+ </script>
231
+
232
+ <style lang="scss" scoped>
233
+ .must {
234
+ width: 4px;
235
+ height: 4px;
236
+ margin-left: 2px;
237
+ margin-top: 5px;
238
+ }
239
+
240
+ .max {
241
+ font-size: 0.6rem;
242
+ }
243
+ </style>