@ramathibodi/nuxt-commons 0.1.61 → 0.1.63

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/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.61",
7
+ "version": "0.1.63",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -12,11 +12,10 @@ import {
12
12
  watch,
13
13
  withDefaults
14
14
  } from 'vue'
15
- import {isObject} from 'lodash-es'
16
15
  import {watchDebounced} from '@vueuse/core'
17
16
  import {useRules} from '../../composables/utils/validation'
18
17
  import {useDocumentTemplate} from '../../composables/document/template'
19
- import { isArray, isString, isPlainObject, isEqual } from 'lodash-es'
18
+ import { isObject, isArray, isString, isPlainObject, isEqual } from 'lodash-es'
20
19
  import FormPad from './Pad.vue'
21
20
 
22
21
  defineOptions({
@@ -85,7 +84,7 @@ const formInjected = ref()
85
84
  const formData = ref<any>({})
86
85
 
87
86
  function isBlankString(v: unknown): v is string {
88
- return isString(v) && v.length === 0
87
+ return isString(v) && v.trim().length === 0
89
88
  }
90
89
 
91
90
  function sanitizeBlankStrings(val: any, original?: any): void {
@@ -101,6 +100,8 @@ function sanitizeBlankStrings(val: any, original?: any): void {
101
100
  val.splice(i, 1)
102
101
  } else if (isPlainObject(item) || isArray(item)) {
103
102
  sanitizeBlankStrings(item,{})
103
+ } else {
104
+ if (item && typeof item.trimEnd == "function") val[i] = item.trimEnd()
104
105
  }
105
106
  }
106
107
  return
@@ -111,9 +112,12 @@ function sanitizeBlankStrings(val: any, original?: any): void {
111
112
  const v = val[key]
112
113
  if (isBlankString(v)) {
113
114
  if (original && !Object.keys(original).includes(key)) delete val[key]
115
+ else val[key] = null
114
116
  } else if (isPlainObject(v) || isArray(v)) {
115
117
  let originalChild = (original && (isPlainObject(original[key]) || isArray(original[key]))) ? original[key] : {}
116
118
  sanitizeBlankStrings(v, originalChild)
119
+ } else {
120
+ if (v && typeof v.trimEnd == "function") val[key] = v.trimEnd()
117
121
  }
118
122
  }
119
123
  }
@@ -128,6 +132,37 @@ watch(() => props.modelValue, (newValue) => {
128
132
  formData.value = isObject(newValue) ? newValue : {}
129
133
  }, { deep: true, immediate: true })
130
134
 
135
+ function diffPaths(
136
+ a: any,
137
+ b: any,
138
+ base: string[] = [],
139
+ out: string[] = []
140
+ ): string[] {
141
+ const keys = new Set<string>([
142
+ ...Object.keys(a ?? {}),
143
+ ...Object.keys(b ?? {}),
144
+ ])
145
+
146
+ for (const k of keys) {
147
+ const av = a?.[k]
148
+ const bv = b?.[k]
149
+ if (!av && !bv) continue // ignore when both are falsy
150
+
151
+ const path = [...base, k]
152
+
153
+ if (isPlainObject(av) && isPlainObject(bv)) {
154
+ diffPaths(av, bv, path, out)
155
+ continue
156
+ }
157
+
158
+ if (!isEqual(av, bv)) {
159
+ out.push(path.join('.'))
160
+ }
161
+ }
162
+
163
+ return out
164
+ }
165
+
131
166
  const injectedClass = computed<Record<string, string>>(() => {
132
167
  const data = (formData.value ?? {}) as Record<string, any>
133
168
  const result: Record<string, string> = {}
@@ -135,13 +170,11 @@ const injectedClass = computed<Record<string, string>>(() => {
135
170
  if (!props.dirtyOnCreate && !props.originalData) return result
136
171
 
137
172
  const original = (props.originalData ?? {}) as Record<string, any>
173
+ const cls = props.dirtyClass || 'form-data-dirty'
174
+
175
+ const paths = diffPaths(data, original)
176
+ for (const p of paths) result[p] = cls
138
177
 
139
- for (const key of Object.keys(data)) {
140
- if (!isEqual(data[key], original[key])) {
141
- if (!data[key] && !original[key]) continue
142
- result[key] = props.dirtyClass || 'form-data-dirty'
143
- }
144
- }
145
178
  return result
146
179
  })
147
180
 
@@ -282,5 +315,5 @@ defineExpose({
282
315
  />
283
316
  </template>
284
317
  <style>
285
- .form-data-dirty,.form-data-dirty *{color:color-mix(in srgb,currentColor 70%,rgb(var(--v-theme-primary)))!important;text-shadow:0 0 .02em currentColor}
318
+ .form-data-dirty,.form-data-dirty:not(.v-input--error) *{color:color-mix(in srgb,currentColor 70%,rgb(var(--v-theme-primary)))!important;text-shadow:0 0 .02em currentColor}
286
319
  </style>
@@ -10,10 +10,16 @@ defineOptions({
10
10
  })
11
11
 
12
12
  interface Props extends /* @vue-ignore */ InstanceType<typeof EditPad['$props']> {
13
+ title?: string
14
+ saveCaption?: string
15
+ cancelCaption?: string
13
16
  }
14
17
 
15
18
  const props = withDefaults(defineProps<Props & GraphqlModelItemProps>(), {
16
19
  fields: () => ['*'],
20
+
21
+ saveCaption: 'บันทึก',
22
+ cancelCaption: 'ยกเลิก',
17
23
  })
18
24
 
19
25
  const emit = defineEmits(['create', 'update'])
@@ -75,7 +81,7 @@ defineExpose({ operation, formPad: editPad.value?.formPad })
75
81
  :disabled="!slotData.operation?.isDataChange || !canSave"
76
82
  @click="slotData.operation?.save"
77
83
  >
78
- {{ saveCaption }}
84
+ {{ props.saveCaption }}
79
85
  </VBtn>
80
86
  <VBtn
81
87
  color="error"
@@ -83,15 +89,13 @@ defineExpose({ operation, formPad: editPad.value?.formPad })
83
89
  :disabled="isLoading"
84
90
  @click="slotData.operation?.cancel"
85
91
  >
86
- {{ cancelCaption }}
92
+ {{ props.cancelCaption }}
87
93
  </VBtn>
88
94
  </slot>
89
95
  </template>
90
96
  <template #default="slotData">
91
97
  <slot
92
98
  v-bind="slotData"
93
- :is-creating="isCreating"
94
- :is-data-change="isDataChange"
95
99
  />
96
100
  </template>
97
101
  </FormEditPad>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.61",
3
+ "version": "0.1.63",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",