tracked-instance 1.0.11 → 1.0.12

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/README.md CHANGED
@@ -71,6 +71,7 @@ useTrackedInstance([1,2,3])
71
71
  ```
72
72
 
73
73
  ### Real-world example
74
+ [Try on playground](https://play.vuejs.org/#eNqNVc1u00AQfpXBl7RSapfCAVlJVGh7KEiloj36srEn8TbrtbU/aaMoz4DEjROvgYTEw/AC8AjM7tqpaarSm+d/vplv1uvobdPES4tRGo10rnhjQKOxzSSTvGpqZWBtNV4rli+wOJfaMJnjBmaqrmBggvqAt/pBJjOZ1yTBumCGDSEvmZxjceoFrk+5MqshKKQaQxA185YNjGG3yN46kwCGG4EpDAZDJ62QqRSkFcKLXF/aqeC6xCKFGRMavbpAw7jQKfgMAEkCuqytKGCKYBvqDOlzta3vvDaZ3Oy79sk5uACX3HAmwCGBW24ohYGKLRBmtaqgcFgy2SUJ7XJq5KVvomv8ukQ4ZWoBHySfl6aP4+jw8M0uDqPs4zCoIOampsBWASBZ5WqclIprUzclKrioBZMDh9l3qRHbJWgCBBK1A79kwqIOWQh5D37YnmZLPGmjxrC3D+NJKLpF64YS+zQURtGjJLCHeEOCwaoRNEOSAEYFX07a3VPv644HsNmMEmfzTqWCJHxNrTG1hONc8HwxziLPliya/Pr64/f3z/DJiaMkePlyFOOxHms7rbiJG4VLlIZCezgoQcA74rKxppvg8qCqCxTk6xH5rWVRZzWrBslk8I4aaMn0VJpY2mqKqsvm1ryTLLg8K12Xp8ePnXR5ifliWt/1Ez4jZUuuuCNV7Kj0X+Bt4jD7B75h+Pcp0oJrNhVYkO1Fu/LO2oIG+PPty0+4oi11JG0r3K/XCW673abLo0nYaOEPMx0lpPEWWvuE2NV7cjzDnNrxs8fJaBiFx+2gYk18o2tJz5/nd9YaiC7bM6MxPHjnnDGLSmManSaJlc1iHud1lez6dbdFFY2m25rx+YN6FNdwgepjYzjd3j91mRD17Xuv274KPsbt/BH9jSYauNYu3c2oJTWwtRmm5u6MnPns6sIvdmskaljH+yeMdHa1sK7H4PbOyoLa7vn5bs/9+LicX+uzO4NSd6Bco34a3j+L6J9z8gT0+3Zfxa+3U9z8BYQrOQM=)
74
75
  ```vue
75
76
  <script setup>
76
77
  import {useTrackedInstance} from 'tracked-instance'
@@ -78,28 +79,66 @@ useTrackedInstance([1,2,3])
78
79
  const {data, changedData, isDirty, reset, loadData} = useTrackedInstance({
79
80
  title: '',
80
81
  year: null,
81
- isPublished: false
82
+ isPublished: false,
83
+ details: {
84
+ // should be updated by loadData
85
+ }
82
86
  })
83
87
 
88
+ // update initial data without make form dirty
84
89
  loadData({
85
90
  id: 1,
86
91
  title: 'The Dark Knight',
87
92
  year: 2008,
88
- isPublished: true
93
+ isPublished: true,
94
+ details: {
95
+ director: {
96
+ name: 'Christopher Nolan' // form see changes in nested values
97
+ }
98
+ }
89
99
  })
100
+
101
+ const saveChanges = () => {
102
+ loadData(data.value)
103
+ }
90
104
  </script>
91
105
 
92
106
  <template>
93
- <button @click="reset">reset</button>
94
-
95
- <form @submit.prevent="console.log(changedData.value)">
96
- <input v-model="data.title" type="text">
97
- <input v-model.number="data.year" type="text">
98
- <input v-model="data.isPublished" type="checkbox">
99
-
100
- <button type="submit" :disabled="!isDirty">Show changed data</button>
107
+ <div>isDirty: {{ isDirty }}</div>
108
+ <hr />
109
+ <button @click="reset">♻️ Reset</button>
110
+
111
+ <form @submit.prevent="saveChanges">
112
+ <input
113
+ v-model="data.title"
114
+ type="text"
115
+ />
116
+ <input
117
+ v-model.number="data.year"
118
+ type="number"
119
+ />
120
+ <input
121
+ v-model="data.isPublished"
122
+ type="checkbox"
123
+ />
124
+
125
+ <input
126
+ v-model="data.details.director.name"
127
+ type="text"
128
+ />
129
+
130
+ <button
131
+ type="submit"
132
+ :disabled="!isDirty"
133
+ >
134
+ 💾 Save changes
135
+ </button>
101
136
  </form>
137
+
138
+ <h2>Changed data:</h2>
139
+ <pre>{{ changedData }}</pre>
102
140
  </template>
141
+
103
142
  ```
104
143
 
105
144
  ## Collection
@@ -148,46 +187,68 @@ console.log(items.value[0].meta.isValidName.value) // false
148
187
  ```
149
188
 
150
189
  ### Real-world example
190
+ [Try on playground](https://play.vuejs.org/#eNp9VcFu1DAQ/ZUhl81K2+QAp9W2orQ90ENBLZwIBzfx7rrrOJHtbLda5RsQSAhxob+BhMTH8AP0ExjbSdZJu+xlbc945s2b58k2OC7LaF3RYBrMVCpZqUFRXZVHiWB5WUgNW0nnNcxlkcMIHUc7Q6XoScE5TTUrROuiJUlXNDtgQmkiUuOfiLTAHWyZOmVS302AZNkEmKa5moCkebGm5h8TT4AXJDslmtRwCL0E4dhEas3hh60gOZ3C6BzzjeoJdPtiKfp7Oqo/2ssOhqC37xWVF2jGHFhdOBp5ZkXW9GRJxIIqNIdjODyCbSKgQxZa4NGa8IpGOSlDe2D9zCJqK48ydHZuY4xfJ2IWO4qRXNygb8mJprgDmF1XWhd4DPibZkyRa06zwyR41pCWBM72MuUsXaHBw+lsNg7Aw/2X33CFRkgbqwkfu/h+rl0oS30SHP35/uvvz09wabb9G0sJsUWN64ytjxpQU9huoVlDXc9iY/PcHKLjLDOkm3bKqTuaMVFW2q0B1gd5kVGOSLzetAUD6LuSok3TDYJ0hwaMjTMsBZUVNp33YtVjU92PrxaKgdGvzodd8TZ02x+ENy8kxrZ9Rt2KjG7G+OcUjJFboDPO0JnNbdusFNSlVXfmZOC5Dino07BPR5GpbEfMHnJ8gp4kyT250BWCoB7uv33GrpvDHjG9632kvSIv6G1boO/V5euXY9WGr9nz9bIB+Cr0UDwGZhM7CQ5woBa7nsSctR2N+08utr02y6ZLrqFWop4ObFOdAoy9a3w0Z1xTic/fvf1htw2zLYoO456e+oCH3XpKSTiZ5oQro6iWLhyU1zgKBzx15TfV9jgIJoGb5Qc4xqIbVQj8DNhZh1mtAdWNBLtQKLLBbDfGJFhqXappHFeiXC2itMjjx34mAlZYY0atcM7O2WKQD++VjFP5pjTDvp+XcF7cntszLSs6ac/TJU1XT5zfqI2D9tZoTa4RQGfTRC7MsDPms6sL+2w6I76/ijdl7TGiLAteGYzO7VUlMoTt+Vm0ry19TCzeqbONpkK1RRmglg3rnwT4ST35T+k7uM+jFx2L9T/LBo48)
151
191
  ```vue
152
192
  <script setup>
153
- import {ref} from 'vue'
154
- import {useCollection} from 'tracked-instance'
193
+ import {ref} from 'vue'
194
+ import {useCollection} from 'tracked-instance'
155
195
 
156
- const {isDirty, add, items, remove, reset, loadData} = useCollection()
196
+ const {isDirty, add, items, remove, reset, loadData} = useCollection()
157
197
 
158
- loadData([{name: 'Jack'}, {name: 'John'}, {name: 'Joe'}])
198
+ loadData([{name: 'Jack'}, {name: 'John'}, {name: 'Joe'}])
199
+
200
+ const newUserName = ref('')
159
201
 
160
- const newUserName = ref('')
202
+ const saveChanges = () => {
203
+ loadData(items.value.map((item) => item.instance.data.value))
204
+ }
161
205
  </script>
162
206
 
163
207
  <template>
208
+ <button
209
+ :disabled="!isDirty"
210
+ @click="saveChanges"
211
+ >
212
+ 💾 Save changes
213
+ </button>
214
+ <button @click="reset">♻️ Reset</button>
215
+ <hr />
216
+
217
+ <div>isDirty: {{ isDirty }}</div>
218
+
164
219
  <div>
165
- isDirty: {{isDirty}}
220
+ Add new user:
221
+ <input
222
+ v-model="newUserName"
223
+ type="text"
224
+ />
225
+ <button @click="add({name: newUserName})">➕ Add user</button>
166
226
  </div>
167
227
 
168
- <button @click="reset">Reset</button>
169
-
170
- <div>
171
- Add new user:
172
- <input v-model="newUserName" type="text">
173
- <button @click="add({name: newUserName})">➕ Add user</button>
174
- </div>
175
-
176
228
  <ul>
177
229
  <template v-for="(item, index) in items">
178
- <li v-if="!item.isRemoved">
179
- <input v-model="item.instance.data.value.name" type="text">
180
- <button @click="remove(index)">♻️ Rollback</button>
230
+ <li v-if="!item.isRemoved.value">
231
+ <input
232
+ v-model="item.instance.data.value.name"
233
+ type="text"
234
+ />
181
235
  <button @click="remove(index)">🗑 Remove</button>
236
+ <button
237
+ v-if="!item.isNew.value"
238
+ @click="item.instance.reset()"
239
+ >
240
+ ♻️ Reset
241
+ </button>
242
+ isNew: {{ item.isNew.value }}
182
243
  </li>
183
244
  </template>
184
245
  </ul>
185
246
 
186
247
  Removed items:
187
248
  <ul>
188
- <li v-for="item in items.filter()">
189
- {{item.instance.data.name}}
190
- <button @click="item.isRemoved = false">♻️ Rollback</button>
249
+ <li v-for="item in items.filter((i) => i.isRemoved.value)">
250
+ {{ item.instance.data.value.name }}
251
+ <button @click="item.isRemoved.value = false">♻️ Rollback</button>
191
252
  </li>
192
253
  </ul>
193
254
  </template>
@@ -0,0 +1,17 @@
1
+ import { ShallowRef, ComputedRef, Ref } from 'vue';
2
+ import { TrackedInstance } from './tracked-instance';
3
+ export interface CollectionItem<Item extends Record<string, any>, Meta = Record<string, any>> {
4
+ instance: TrackedInstance<Item>;
5
+ meta: Meta;
6
+ isRemoved: Ref<boolean>;
7
+ isNew: Ref<boolean>;
8
+ }
9
+ export interface Collection<Item extends Record<string, any>, Meta = Record<string, any>> {
10
+ items: ShallowRef<CollectionItem<Item, Meta>[]>;
11
+ isDirty: ComputedRef<boolean>;
12
+ add: (item: Partial<Item>, afterIndex?: number) => CollectionItem<Item, Meta>;
13
+ remove: (index: number, isHardRemove?: boolean) => void;
14
+ loadData: (items: Item[]) => void;
15
+ reset: () => void;
16
+ }
17
+ export declare const useCollection: <Item extends Record<string, any>, Meta = Record<string, any>>(createItemMeta?: (instance: TrackedInstance<Item>) => Meta) => Collection<Item, Meta>;
@@ -0,0 +1,4 @@
1
+ export type { TrackedInstance } from './tracked-instance';
2
+ export type { Collection, CollectionItem } from './collection';
3
+ export { useTrackedInstance } from './tracked-instance';
4
+ export { useCollection } from './collection';
@@ -0,0 +1,13 @@
1
+ import { Ref } from 'vue';
2
+ type DeepPartial<T> = T extends object ? {
3
+ [P in keyof T]?: DeepPartial<T[P]>;
4
+ } : T;
5
+ export interface TrackedInstance<Data extends Record<string, any>> {
6
+ data: Ref<Data>;
7
+ isDirty: Ref<boolean>;
8
+ changedData: Ref<DeepPartial<Data>>;
9
+ loadData: (newData: DeepPartial<Data>) => void;
10
+ reset: () => void;
11
+ }
12
+ export declare const useTrackedInstance: <Data extends Record<string, any>>(initialData: Partial<Data>) => TrackedInstance<Data>;
13
+ export {};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "tracked-instance",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Build large forms and track all changes",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "esbuild ./src/index.ts --bundle --external:vue --outfile=./dist/index.mjs --format=esm",
7
+ "build": "tsc && esbuild ./src/index.ts --bundle --external:vue --outfile=./dist/index.mjs --format=esm",
8
8
  "test": "vitest run"
9
9
  },
10
10
  "main": "./dist/index.mjs",