@dragonmastery/zinia-forms-core 0.3.10 → 0.3.11

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/index.d.ts CHANGED
@@ -882,6 +882,8 @@ interface TextareaFieldProps<FormType> {
882
882
  size?: string;
883
883
  variant?: string;
884
884
  rows?: number;
885
+ autoExpand?: boolean;
886
+ maxRows?: number;
885
887
  }
886
888
 
887
889
  interface TextFieldProps<FormType> {
@@ -1359,6 +1361,11 @@ declare function useForm<T extends z.ZodObject<any>, CalcType = (values: z.infer
1359
1361
  getDisplayText: (path: string) => string;
1360
1362
  setSelectedIndex: (path: string, index: number) => void;
1361
1363
  getSelectedIndex: (path: string) => number;
1364
+ getArrayItemId: (path: string, index: number) => string;
1365
+ addArrayItemId: (path: string, index?: number) => string;
1366
+ removeArrayItemId: (path: string, index: number) => void;
1367
+ swapArrayItemIds: (path: string, indexA: number, indexB: number) => void;
1368
+ syncArrayItemIds: (path: string) => void;
1362
1369
  };
1363
1370
  ZiniaForm: vue.FunctionalComponent<FormProps<z.TypeOf<T>>, {}, any, {}>;
1364
1371
  ZiniaSubmitButton: vue.FunctionalComponent<SubmitButtonProps<z.TypeOf<T>>, {}, any, {}>;
package/dist/index.js CHANGED
@@ -849,6 +849,71 @@ function setFieldSelectedIndex(formState, path, index) {
849
849
  function getFieldSelectedIndex(formState, path) {
850
850
  return formState.selectedIndex[path] ?? -1;
851
851
  }
852
+ function generateArrayItemId() {
853
+ return `item-${Math.random().toString(36).substr(2, 9)}-${Date.now()}`;
854
+ }
855
+ function getArrayItemId(formState, path, index) {
856
+ if (!formState.arrayItemIds[path]) {
857
+ formState.arrayItemIds[path] = [];
858
+ }
859
+ const ids = formState.arrayItemIds[path];
860
+ const arrayValue = getFieldValue(formState, path);
861
+ const arrayLength = Array.isArray(arrayValue) ? arrayValue.length : 0;
862
+ while (ids.length < arrayLength) {
863
+ ids.push(generateArrayItemId());
864
+ }
865
+ if (index >= ids.length) {
866
+ ids.push(generateArrayItemId());
867
+ }
868
+ return ids[index];
869
+ }
870
+ function addArrayItemId(formState, path, index) {
871
+ if (!formState.arrayItemIds[path]) {
872
+ formState.arrayItemIds[path] = [];
873
+ }
874
+ const ids = formState.arrayItemIds[path];
875
+ const newId = generateArrayItemId();
876
+ if (index !== void 0 && index >= 0 && index <= ids.length) {
877
+ ids.splice(index, 0, newId);
878
+ } else {
879
+ ids.push(newId);
880
+ }
881
+ return newId;
882
+ }
883
+ function removeArrayItemId(formState, path, index) {
884
+ if (!formState.arrayItemIds[path]) {
885
+ return;
886
+ }
887
+ const ids = formState.arrayItemIds[path];
888
+ if (index >= 0 && index < ids.length) {
889
+ ids.splice(index, 1);
890
+ }
891
+ }
892
+ function swapArrayItemIds(formState, path, indexA, indexB) {
893
+ if (!formState.arrayItemIds[path]) {
894
+ return;
895
+ }
896
+ const ids = formState.arrayItemIds[path];
897
+ if (indexA >= 0 && indexA < ids.length && indexB >= 0 && indexB < ids.length) {
898
+ const temp = ids[indexA];
899
+ ids[indexA] = ids[indexB];
900
+ ids[indexB] = temp;
901
+ }
902
+ }
903
+ function syncArrayItemIds(formState, path) {
904
+ const arrayValue = getFieldValue(formState, path);
905
+ const arrayLength = Array.isArray(arrayValue) ? arrayValue.length : 0;
906
+ if (!formState.arrayItemIds[path]) {
907
+ formState.arrayItemIds[path] = [];
908
+ }
909
+ const ids = formState.arrayItemIds[path];
910
+ while (ids.length < arrayLength) {
911
+ ids.push(generateArrayItemId());
912
+ }
913
+ if (ids.length > arrayLength) {
914
+ ids.splice(arrayLength);
915
+ }
916
+ }
852
917
 
853
918
  // src/registry/metadataRegistry.ts
854
919
  var globalRegistry = {};
@@ -1526,6 +1591,7 @@ function useFormState(initialData, options) {
1526
1591
  undoHistory: {},
1527
1592
  redoHistory: {},
1528
1593
  pendingOperations: {},
1594
+ arrayItemIds: {},
1529
1595
  // Form status
1530
1596
  isSubmitting: false,
1531
1597
  hasAttemptedSubmit: false,
@@ -2009,7 +2075,13 @@ function useForm(schema, options) {
2009
2075
  setDisplayText: (path, text) => setFieldDisplayText(formState.state, path, text),
2010
2076
  getDisplayText: (path) => getFieldDisplayText(formState.state, path),
2011
2077
  setSelectedIndex: (path, index) => setFieldSelectedIndex(formState.state, path, index),
2012
- getSelectedIndex: (path) => getFieldSelectedIndex(formState.state, path)
2078
+ getSelectedIndex: (path) => getFieldSelectedIndex(formState.state, path),
2079
+ // Array item ID management (for stable keys in ArrayField)
2080
+ getArrayItemId: (path, index) => getArrayItemId(formState.state, path, index),
2081
+ addArrayItemId: (path, index) => addArrayItemId(formState.state, path, index),
2082
+ removeArrayItemId: (path, index) => removeArrayItemId(formState.state, path, index),
2083
+ swapArrayItemIds: (path, indexA, indexB) => swapArrayItemIds(formState.state, path, indexA, indexB),
2084
+ syncArrayItemIds: (path) => syncArrayItemIds(formState.state, path)
2013
2085
  };
2014
2086
  if (options.autoProvide !== false) {
2015
2087
  provide(ZINIA_FORM_SCHEMA_KEY, schema);
@@ -3736,6 +3808,7 @@ function createDaisyUIArrayField() {
3736
3808
  }
3737
3809
  const fieldMetadata = formState.fieldsMetadata[props.name] || {};
3738
3810
  const arrayValue = formState.getValue(props.name) || [];
3811
+ formState.syncArrayItemIds(props.name);
3739
3812
  const fieldName = String(props.name);
3740
3813
  if (!formState.collapsedFields[fieldName]) {
3741
3814
  formState.collapsedFields[fieldName] = {
@@ -3874,7 +3947,19 @@ function createDaisyUIArrayField() {
3874
3947
  const currentActualArray = formState.getValue(props.name) || [];
3875
3948
  const newArray = [...currentActualArray];
3876
3949
  const removedItem = newArray[opToConfirm.index];
3877
- newArray.splice(opToConfirm.index, 1);
3950
+ const removedIndex = opToConfirm.index;
3951
+ newArray.splice(removedIndex, 1);
3952
+ formState.removeArrayItemId(props.name, removedIndex);
3953
+ const collapsedItems = collapseState.collapsedItems;
3954
+ const deletedIndexPos = collapsedItems.indexOf(removedIndex);
3955
+ if (deletedIndexPos > -1) {
3956
+ collapsedItems.splice(deletedIndexPos, 1);
3957
+ }
3958
+ for (let i = 0; i < collapsedItems.length; i++) {
3959
+ if (collapsedItems[i] > removedIndex) {
3960
+ collapsedItems[i] = collapsedItems[i] - 1;
3961
+ }
3962
+ }
3878
3963
  formState.setValue(props.name, newArray);
3879
3964
  formState.validateField(props.name);
3880
3965
  const instance = getCurrentInstance();
@@ -3886,10 +3971,10 @@ function createDaisyUIArrayField() {
3886
3971
  }
3887
3972
  formState.pendingOperations[fieldName] = ops.filter((op) => op.timestamp !== opToConfirm.timestamp);
3888
3973
  if (opToConfirm.type === "remove" && opToConfirm.index !== void 0) {
3889
- const removedIndex = opToConfirm.index;
3974
+ const removedIndex2 = opToConfirm.index;
3890
3975
  const remainingOps = formState.pendingOperations[fieldName];
3891
3976
  const updatedOps = remainingOps.map((op) => {
3892
- if (op.type === "remove" && op.index !== void 0 && op.index > removedIndex) {
3977
+ if (op.type === "remove" && op.index !== void 0 && op.index > removedIndex2) {
3893
3978
  const newIndex = op.index - 1;
3894
3979
  const currentArray = formState.getValue(props.name) || [];
3895
3980
  const newCurrentState = [...currentArray];
@@ -3942,6 +4027,7 @@ function createDaisyUIArrayField() {
3942
4027
  }
3943
4028
  const itemCopy = JSON.parse(JSON.stringify(item));
3944
4029
  const newArray = [...currentArray, itemCopy];
4030
+ formState.addArrayItemId(props.name, newArray.length - 1);
3945
4031
  formState.setValue(props.name, newArray);
3946
4032
  formState.validateField(props.name);
3947
4033
  if (props.onAddItem) {
@@ -3965,6 +4051,17 @@ function createDaisyUIArrayField() {
3965
4051
  createPendingOperation("remove", previousState, newArray, index);
3966
4052
  return;
3967
4053
  }
4054
+ formState.removeArrayItemId(props.name, index);
4055
+ const collapsedItems = collapseState.collapsedItems;
4056
+ const deletedIndexPos = collapsedItems.indexOf(index);
4057
+ if (deletedIndexPos > -1) {
4058
+ collapsedItems.splice(deletedIndexPos, 1);
4059
+ }
4060
+ for (let i = 0; i < collapsedItems.length; i++) {
4061
+ if (collapsedItems[i] > index) {
4062
+ collapsedItems[i] = collapsedItems[i] - 1;
4063
+ }
4064
+ }
3968
4065
  formState.setValue(props.name, newArray);
3969
4066
  formState.validateField(props.name);
3970
4067
  if (props.onRemoveItem) {
@@ -3984,6 +4081,7 @@ function createDaisyUIArrayField() {
3984
4081
  const temp = newArray[indexA];
3985
4082
  newArray[indexA] = newArray[indexB];
3986
4083
  newArray[indexB] = temp;
4084
+ formState.swapArrayItemIds(props.name, indexA, indexB);
3987
4085
  formState.setValue(props.name, newArray);
3988
4086
  formState.validateField(props.name);
3989
4087
  if (props.onSwapItems) {
@@ -4180,11 +4278,14 @@ function createDaisyUIArrayField() {
4180
4278
  `remove-${itemPendingOp.timestamp}`
4181
4279
  );
4182
4280
  }
4183
- const itemKey = `item-${index}-${JSON.stringify(item).substring(0, 50)}`;
4281
+ const itemId = formState.getArrayItemId(props.name, index);
4282
+ const itemKey = `item-${index}-${itemId}`;
4184
4283
  return /* @__PURE__ */ jsxs(
4185
4284
  "div",
4186
4285
  {
4187
4286
  class: "border border-base-300 rounded-lg bg-base-100 shadow-sm hover:shadow-md transition-shadow",
4287
+ "data-item-key": itemKey,
4288
+ "data-item-index": index,
4188
4289
  children: [
4189
4290
  /* @__PURE__ */ jsxs("div", { class: "border-b border-base-200 bg-base-50 rounded-t-lg", children: [
4190
4291
  /* @__PURE__ */ jsxs("div", { class: "flex items-center justify-between gap-2 p-1 sm:p-3 sm:px-4", children: [
@@ -6192,11 +6293,47 @@ function createDaisyUITextareaField() {
6192
6293
  return null;
6193
6294
  }
6194
6295
  const fieldMetadata = formState.fieldsMetadata[props.name] || {};
6296
+ const textareaRef = ref(null);
6297
+ const autoExpand = props.autoExpand !== false;
6298
+ const defaultMaxRows = 10;
6299
+ const maxRows = props.maxRows ?? (autoExpand ? defaultMaxRows : void 0);
6300
+ const minRows = props.rows ?? 3;
6301
+ const getLineHeight = () => {
6302
+ const textarea = textareaRef.value;
6303
+ if (!textarea) return 24;
6304
+ const style = window.getComputedStyle(textarea);
6305
+ const lineHeight = parseFloat(style.lineHeight);
6306
+ return isNaN(lineHeight) ? 24 : lineHeight;
6307
+ };
6308
+ const autoResize = async () => {
6309
+ const textarea = textareaRef.value;
6310
+ if (!textarea || !autoExpand) return;
6311
+ textarea.style.height = "auto";
6312
+ await nextTick();
6313
+ const scrollHeight = textarea.scrollHeight;
6314
+ const lineHeight = getLineHeight();
6315
+ const minHeight = minRows * lineHeight;
6316
+ const maxHeight = maxRows ? maxRows * lineHeight : void 0;
6317
+ const newHeight = maxHeight ? Math.min(Math.max(scrollHeight, minHeight), maxHeight) : Math.max(scrollHeight, minHeight);
6318
+ textarea.style.height = `${newHeight}px`;
6319
+ textarea.style.overflowY = maxHeight && scrollHeight > maxHeight ? "auto" : "hidden";
6320
+ };
6321
+ const setTextareaRef = (el) => {
6322
+ textareaRef.value = el;
6323
+ if (el && autoExpand && formState.getValue(props.name)) {
6324
+ nextTick(() => {
6325
+ autoResize();
6326
+ });
6327
+ }
6328
+ };
6195
6329
  const textareaProps = {
6196
6330
  value: formState.getValue(props.name),
6197
- onInput: (event) => {
6331
+ onInput: async (event) => {
6198
6332
  const target = event.target;
6199
6333
  formState.setValue(props.name, target.value);
6334
+ if (autoExpand) {
6335
+ await autoResize();
6336
+ }
6200
6337
  },
6201
6338
  onBlur: () => {
6202
6339
  formState.touchField(props.name);
@@ -6223,6 +6360,7 @@ function createDaisyUITextareaField() {
6223
6360
  /* @__PURE__ */ jsx(
6224
6361
  "textarea",
6225
6362
  {
6363
+ ref: setTextareaRef,
6226
6364
  class: textareaClass,
6227
6365
  placeholder: props.placeholder,
6228
6366
  disabled: props.disabled,
@@ -6248,7 +6386,9 @@ function createDaisyUITextareaField() {
6248
6386
  "required",
6249
6387
  "size",
6250
6388
  "variant",
6251
- "rows"
6389
+ "rows",
6390
+ "autoExpand",
6391
+ "maxRows"
6252
6392
  ];
6253
6393
  return DaisyUITextareaField;
6254
6394
  }