@hybridly/vue 0.1.0-alpha.3 → 0.1.0-alpha.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.
package/dist/index.cjs CHANGED
@@ -56,6 +56,8 @@ const dialogStore = {
56
56
  }
57
57
  };
58
58
 
59
+ const onMountedCallbacks = [];
60
+
59
61
  const state = {
60
62
  context: vue.ref(),
61
63
  view: vue.shallowRef(),
@@ -119,10 +121,17 @@ const wrapper = vue.defineComponent({
119
121
  function renderView() {
120
122
  utils.debug.adapter("vue:render:view", "Rendering view.");
121
123
  state.view.value.inheritAttrs = !!state.view.value.inheritAttrs;
122
- return vue.h(state.view.value, {
124
+ return vue.withDirectives(vue.h(state.view.value, {
123
125
  ...state.properties.value,
124
126
  key: state.viewKey.value
125
- });
127
+ }), [[{
128
+ mounted: () => {
129
+ vue.nextTick(() => {
130
+ utils.debug.adapter("vue:render:view", "Calling mounted callbacks.");
131
+ onMountedCallbacks.pop()?.();
132
+ });
133
+ }
134
+ }]]);
126
135
  }
127
136
  function renderDialog() {
128
137
  if (dialogStore.state.component.value && dialogStore.state.properties.value) {
@@ -279,6 +288,9 @@ async function initializeHybridly(options = {}) {
279
288
  responseErrorModals: resolved.responseErrorModals ?? process.env.NODE_ENV === "development",
280
289
  adapter: {
281
290
  resolveComponent: resolve,
291
+ onWaitingForMount: (callback) => {
292
+ onMountedCallbacks.push(callback);
293
+ },
282
294
  onDialogClose: async () => {
283
295
  dialogStore.hide();
284
296
  },
@@ -512,15 +524,10 @@ function toReactive(objectRef) {
512
524
  function useProperties() {
513
525
  return vue.readonly(toReactive(vue.computed(() => state.context.value?.view.properties)));
514
526
  }
515
- function useTypedProperty(path, fallback) {
516
- return vue.computed(
517
- () => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
518
- );
519
- }
520
- function useProperty(path, fallback) {
521
- return vue.computed(
522
- () => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
523
- );
527
+ function useProperty(path) {
528
+ return vue.computed(() => {
529
+ return path.split(".").reduce((o, i) => o?.[i], state.context.value?.view.properties);
530
+ });
524
531
  }
525
532
 
526
533
  function useContext() {
@@ -562,6 +569,14 @@ function useForm(options) {
562
569
  Reflect.set(fields, key, safeClone(Reflect.get(initial, key)));
563
570
  });
564
571
  }
572
+ function clear(...keys) {
573
+ if (keys.length === 0) {
574
+ keys = Object.keys(fields);
575
+ }
576
+ keys.forEach((key) => {
577
+ delete fields[key];
578
+ });
579
+ }
565
580
  function submit(optionsOverrides) {
566
581
  const url = typeof options.url === "function" ? options.url() : options.url;
567
582
  const data = typeof options.transform === "function" ? options.transform?.(fields) : fields;
@@ -599,7 +614,9 @@ function useForm(options) {
599
614
  },
600
615
  success: (payload, context) => {
601
616
  clearErrors();
602
- setInitial(fields);
617
+ if (options?.updateInitials) {
618
+ setInitial(fields);
619
+ }
603
620
  if (options?.reset !== false) {
604
621
  reset();
605
622
  }
@@ -634,7 +651,10 @@ function useForm(options) {
634
651
  delete errors.value[key];
635
652
  }
636
653
  function setErrors(incoming) {
637
- errors.value = incoming;
654
+ clearErrors();
655
+ Object.entries(incoming).forEach(([key, value]) => {
656
+ errors.value[key] = value;
657
+ });
638
658
  }
639
659
  function abort() {
640
660
  core.router.abort();
@@ -650,6 +670,7 @@ function useForm(options) {
650
670
  }, { deep: true, immediate: true });
651
671
  return vue.reactive({
652
672
  reset,
673
+ clear,
653
674
  fields,
654
675
  abort,
655
676
  setErrors,
@@ -772,4 +793,3 @@ exports.useHistoryState = useHistoryState;
772
793
  exports.usePaginator = usePaginator;
773
794
  exports.useProperties = useProperties;
774
795
  exports.useProperty = useProperty;
775
- exports.useTypedProperty = useTypedProperty;
package/dist/index.d.ts CHANGED
@@ -181,16 +181,11 @@ declare const RouterLink: vue.DefineComponent<{
181
181
 
182
182
  /** Accesses all current properties. */
183
183
  declare function useProperties<T extends object, Global extends GlobalHybridlyProperties>(): vue.DeepReadonly<vue.UnwrapNestedRefs<T & Global>>;
184
- /**
185
- * Accesses a property with the given type.
186
- * @experimental Workaround for not being able to type `useProperty`, might be removed in the future.
187
- */
188
- declare function useTypedProperty<T>(path: string, fallback?: T): ComputedRef<T>;
189
184
  /** Accesses a property with a dot notation. */
190
- declare function useProperty<T = GlobalHybridlyProperties, P extends Path<T> = Path<T>, Fallback extends PathValue<T, P> = PathValue<T, P>>(path: [P] extends [never] ? string : P, fallback?: Fallback): ComputedRef<[PathValue<T, P>] extends [never] ? Fallback : PathValue<T, P>>;
191
- type PathImpl<T, K extends keyof T> = K extends string ? T[K] extends Record<string, any> ? T[K] extends ArrayLike<any> ? K | `${K}.${PathImpl<T[K], Exclude<keyof T[K], keyof any[]>>}` : K | `${K}.${PathImpl<T[K], keyof T[K]>}` : K : never;
185
+ declare function useProperty<F = never, T = GlobalHybridlyProperties, P extends Path<T> = Path<T>>(path: [F] extends [never] ? ([P] extends [never] ? string : P) : string): ComputedRef<[F] extends [never] ? ([PathValue<T, P>] extends [never] ? never : PathValue<T, P>) : F>;
186
+ type PathImpl<T, K extends keyof T> = K extends string ? T[K] extends undefined ? undefined : NonNullable<T[K]> extends Record<string, any> ? NonNullable<T[K]> extends ArrayLike<any> ? K | `${K}.${PathImpl<NonNullable<T[K]>, Exclude<keyof NonNullable<T[K]>, keyof any[]>>}` : K | `${K}.${PathImpl<NonNullable<T[K]>, keyof NonNullable<T[K]>>}` : K : never;
192
187
  type Path<T> = PathImpl<T, keyof T> | keyof T;
193
- type PathValue<T, P extends Path<T>> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? Rest extends Path<T[K]> ? PathValue<T[K], Rest> : never : never : P extends keyof T ? T[P] : never;
188
+ type PathValue<T, P extends Path<T>> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? T[K] extends undefined ? undefined : Rest extends Path<T[K]> ? PathValue<T[K], Rest> : Rest extends Path<NonNullable<T[K]>> ? PathValue<NonNullable<T[K]>, Rest> | undefined : never : never : P extends keyof T ? T[P] extends undefined ? undefined : T[P] : never;
194
189
 
195
190
  type MaybePromise<T> = T | Promise<T>;
196
191
 
@@ -285,7 +280,7 @@ type BaseUrlTransformable = Partial<Omit<URL, 'searchParams' | 'toJSON' | 'toStr
285
280
  trailingSlash?: boolean;
286
281
  };
287
282
 
288
- type ConditionalNavigationOption = boolean | ((payload: HybridPayload) => boolean);
283
+ type ConditionalNavigationOption<T extends boolean | string> = T | ((payload: NavigationOptions) => T);
289
284
  interface NavigationOptions {
290
285
  /** View to navigate to. */
291
286
  payload?: HybridPayload;
@@ -293,13 +288,13 @@ interface NavigationOptions {
293
288
  * Whether to replace the current history state instead of adding
294
289
  * one. This affects the browser's "back" and "forward" features.
295
290
  */
296
- replace?: ConditionalNavigationOption;
297
- /** Whether to preserve the current scrollbar position. */
298
- preserveScroll?: ConditionalNavigationOption;
291
+ replace?: ConditionalNavigationOption<boolean>;
292
+ /** Whether to preserve the scrollbars positions on the page. */
293
+ preserveScroll?: ConditionalNavigationOption<boolean>;
299
294
  /** Whether to preserve the current page component's state. */
300
- preserveState?: ConditionalNavigationOption;
295
+ preserveState?: ConditionalNavigationOption<boolean>;
301
296
  /** Whether to preserve the current URL. */
302
- preserveUrl?: ConditionalNavigationOption;
297
+ preserveUrl?: ConditionalNavigationOption<boolean>;
303
298
  /**
304
299
  * Properties of the given URL to override.
305
300
  * @example
@@ -463,6 +458,8 @@ interface Adapter {
463
458
  onContextUpdate?: (context: InternalRouterContext) => void;
464
459
  /** Called when a dialog is closed. */
465
460
  onDialogClose?: (context: InternalRouterContext) => void;
461
+ /** Called when Hybridly is waiting for a component to be mounted. The given callback should be executed after the view component is mounted. */
462
+ onWaitingForMount: (callback: Function) => void;
466
463
  }
467
464
  interface ResolvedAdapter extends Adapter {
468
465
  updateRoutingConfiguration: (routing?: RoutingConfiguration) => void;
@@ -485,12 +482,28 @@ interface FormOptions<T extends Fields> extends Omit<HybridRequestOptions$1, 'da
485
482
  fields: T;
486
483
  url?: UrlResolvable$1 | (() => UrlResolvable$1);
487
484
  key?: string | false;
485
+ /**
486
+ * Defines the delay after which the `recentlySuccessful` and `recentlyFailed` variables are reset to `false`.
487
+ */
488
488
  timeout?: number;
489
+ /**
490
+ * Resets the fields of the form to their initial value after a successful submission.
491
+ * @default true
492
+ */
489
493
  reset?: boolean;
494
+ /**
495
+ * Updates the initial values from the form after a successful submission.
496
+ * @default false
497
+ */
498
+ updateInitials?: boolean;
499
+ /**
500
+ * Callback executed before the form submission for transforming the fields.
501
+ */
490
502
  transform?: (fields: T) => Fields;
491
503
  }
492
504
  declare function useForm<T extends Fields = Fields>(options: FormOptions<T>): {
493
505
  reset: (...keys: (keyof T)[]) => void;
506
+ clear: (...keys: (keyof T)[]) => void;
494
507
  fields: vue.UnwrapRef<vue.UnwrapNestedRefs<T>>;
495
508
  abort: () => void;
496
509
  setErrors: (incoming: Record<string, string>) => void;
@@ -645,4 +658,4 @@ declare function useDialog(): {
645
658
  properties: vue.ComputedRef<Properties | undefined>;
646
659
  };
647
660
 
648
- export { Layout, RouterLink, defineLayout, defineLayoutProperties, initializeHybridly, registerHook, resolvePageComponent, useBackForward, useContext, useDialog, useForm, useHistoryState, usePaginator, useProperties, useProperty, useTypedProperty };
661
+ export { Layout, RouterLink, defineLayout, defineLayoutProperties, initializeHybridly, registerHook, resolvePageComponent, useBackForward, useContext, useDialog, useForm, useHistoryState, usePaginator, useProperties, useProperty };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { shallowRef, ref, unref, triggerRef, defineComponent, toRaw, h, createApp, isRef, reactive, readonly, computed, watch, getCurrentInstance, onUnmounted } from 'vue';
1
+ import { shallowRef, ref, unref, triggerRef, defineComponent, toRaw, h, withDirectives, nextTick, createApp, isRef, reactive, readonly, computed, watch, getCurrentInstance, onUnmounted } from 'vue';
2
2
  import { registerHook as registerHook$1, createRouter, makeUrl, router } from '@hybridly/core';
3
3
  export { can, route, router } from '@hybridly/core';
4
4
  import { debug, random, showDomainsDisabledErrorModal, showPageComponentErrorModal, merge, clone } from '@hybridly/utils';
@@ -48,6 +48,8 @@ const dialogStore = {
48
48
  }
49
49
  };
50
50
 
51
+ const onMountedCallbacks = [];
52
+
51
53
  const state = {
52
54
  context: ref(),
53
55
  view: shallowRef(),
@@ -111,10 +113,17 @@ const wrapper = defineComponent({
111
113
  function renderView() {
112
114
  debug.adapter("vue:render:view", "Rendering view.");
113
115
  state.view.value.inheritAttrs = !!state.view.value.inheritAttrs;
114
- return h(state.view.value, {
116
+ return withDirectives(h(state.view.value, {
115
117
  ...state.properties.value,
116
118
  key: state.viewKey.value
117
- });
119
+ }), [[{
120
+ mounted: () => {
121
+ nextTick(() => {
122
+ debug.adapter("vue:render:view", "Calling mounted callbacks.");
123
+ onMountedCallbacks.pop()?.();
124
+ });
125
+ }
126
+ }]]);
118
127
  }
119
128
  function renderDialog() {
120
129
  if (dialogStore.state.component.value && dialogStore.state.properties.value) {
@@ -271,6 +280,9 @@ async function initializeHybridly(options = {}) {
271
280
  responseErrorModals: resolved.responseErrorModals ?? process.env.NODE_ENV === "development",
272
281
  adapter: {
273
282
  resolveComponent: resolve,
283
+ onWaitingForMount: (callback) => {
284
+ onMountedCallbacks.push(callback);
285
+ },
274
286
  onDialogClose: async () => {
275
287
  dialogStore.hide();
276
288
  },
@@ -504,15 +516,10 @@ function toReactive(objectRef) {
504
516
  function useProperties() {
505
517
  return readonly(toReactive(computed(() => state.context.value?.view.properties)));
506
518
  }
507
- function useTypedProperty(path, fallback) {
508
- return computed(
509
- () => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
510
- );
511
- }
512
- function useProperty(path, fallback) {
513
- return computed(
514
- () => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
515
- );
519
+ function useProperty(path) {
520
+ return computed(() => {
521
+ return path.split(".").reduce((o, i) => o?.[i], state.context.value?.view.properties);
522
+ });
516
523
  }
517
524
 
518
525
  function useContext() {
@@ -554,6 +561,14 @@ function useForm(options) {
554
561
  Reflect.set(fields, key, safeClone(Reflect.get(initial, key)));
555
562
  });
556
563
  }
564
+ function clear(...keys) {
565
+ if (keys.length === 0) {
566
+ keys = Object.keys(fields);
567
+ }
568
+ keys.forEach((key) => {
569
+ delete fields[key];
570
+ });
571
+ }
557
572
  function submit(optionsOverrides) {
558
573
  const url = typeof options.url === "function" ? options.url() : options.url;
559
574
  const data = typeof options.transform === "function" ? options.transform?.(fields) : fields;
@@ -591,7 +606,9 @@ function useForm(options) {
591
606
  },
592
607
  success: (payload, context) => {
593
608
  clearErrors();
594
- setInitial(fields);
609
+ if (options?.updateInitials) {
610
+ setInitial(fields);
611
+ }
595
612
  if (options?.reset !== false) {
596
613
  reset();
597
614
  }
@@ -626,7 +643,10 @@ function useForm(options) {
626
643
  delete errors.value[key];
627
644
  }
628
645
  function setErrors(incoming) {
629
- errors.value = incoming;
646
+ clearErrors();
647
+ Object.entries(incoming).forEach(([key, value]) => {
648
+ errors.value[key] = value;
649
+ });
630
650
  }
631
651
  function abort() {
632
652
  router.abort();
@@ -642,6 +662,7 @@ function useForm(options) {
642
662
  }, { deep: true, immediate: true });
643
663
  return reactive({
644
664
  reset,
665
+ clear,
645
666
  fields,
646
667
  abort,
647
668
  setErrors,
@@ -747,4 +768,4 @@ function useDialog() {
747
768
  };
748
769
  }
749
770
 
750
- export { RouterLink, defineLayout, defineLayoutProperties, initializeHybridly, registerHook, resolvePageComponent, useBackForward, useContext, useDialog, useForm, useHistoryState, usePaginator, useProperties, useProperty, useTypedProperty };
771
+ export { RouterLink, defineLayout, defineLayoutProperties, initializeHybridly, registerHook, resolvePageComponent, useBackForward, useContext, useDialog, useForm, useHistoryState, usePaginator, useProperties, useProperty };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hybridly/vue",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.5",
4
4
  "description": "Vue adapter for Hybridly",
5
5
  "keywords": [
6
6
  "hybridly",
@@ -43,10 +43,10 @@
43
43
  "lodash.isequal": "^4.5.0",
44
44
  "nprogress": "^0.2.0",
45
45
  "qs": "^6.11.0",
46
- "@hybridly/config": "0.1.0-alpha.3",
47
- "@hybridly/core": "0.1.0-alpha.3",
48
- "@hybridly/progress-plugin": "0.1.0-alpha.3",
49
- "@hybridly/utils": "0.1.0-alpha.3"
46
+ "@hybridly/config": "0.1.0-alpha.5",
47
+ "@hybridly/core": "0.1.0-alpha.5",
48
+ "@hybridly/progress-plugin": "0.1.0-alpha.5",
49
+ "@hybridly/utils": "0.1.0-alpha.5"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/lodash": "^4.14.191",