ivue 1.0.3 → 1.0.4

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 (101) hide show
  1. package/README.md +23 -7
  2. package/coverage/clover.xml +156 -156
  3. package/coverage/coverage-final.json +1 -1
  4. package/coverage/index.html +17 -17
  5. package/coverage/index.ts.html +70 -85
  6. package/dist/index.es.js +74 -90
  7. package/dist/index.umd.js +1 -1
  8. package/dist/src/index.d.ts +1 -199
  9. package/dist/src/ivue.d.ts +218 -0
  10. package/docs/docs/.vitepress/config.ts +94 -29
  11. package/docs/docs/.vitepress/dist/404.html +4 -4
  12. package/docs/docs/.vitepress/dist/api/ivue.html +6 -6
  13. package/docs/docs/.vitepress/dist/api/propsWithDefaults.html +6 -6
  14. package/docs/docs/.vitepress/dist/assets/{app.CbDr3eFe.js → app.ConZRsN0.js} +1 -1
  15. package/docs/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.CGLWArGd.js +1 -0
  16. package/docs/docs/.vitepress/dist/assets/chunks/{VPLocalSearchBox.C1TPvqwb.js → VPLocalSearchBox.C7VDyivS.js} +1 -1
  17. package/docs/docs/.vitepress/dist/assets/chunks/index.es.DnWLDAUc.js +1 -0
  18. package/docs/docs/.vitepress/dist/assets/chunks/{theme.DSY3Mj9W.js → theme.B7n-r1TY.js} +2 -2
  19. package/docs/docs/.vitepress/dist/assets/index.md.wPLoTLBY.js +1 -0
  20. package/docs/docs/.vitepress/dist/assets/index.md.wPLoTLBY.lean.js +1 -0
  21. package/docs/docs/.vitepress/dist/assets/pages_advanced-usage.md.BZgX-VP7.js +1 -0
  22. package/docs/docs/.vitepress/dist/assets/pages_advanced-usage.md.BZgX-VP7.lean.js +1 -0
  23. package/docs/docs/.vitepress/dist/assets/pages_api.md.C_PvCZns.js +7 -0
  24. package/docs/docs/.vitepress/dist/assets/pages_api.md.C_PvCZns.lean.js +7 -0
  25. package/docs/docs/.vitepress/dist/assets/pages_browse-code.md.CPluoaap.js +1 -0
  26. package/docs/docs/.vitepress/dist/assets/pages_browse-code.md.CPluoaap.lean.js +1 -0
  27. package/docs/docs/.vitepress/dist/assets/pages_getting-started.md.knQcOZyP.js +8 -0
  28. package/docs/docs/.vitepress/dist/assets/pages_getting-started.md.knQcOZyP.lean.js +1 -0
  29. package/docs/docs/.vitepress/dist/assets/pages_guidelines.md.DddPdPom.js +101 -0
  30. package/docs/docs/.vitepress/dist/assets/pages_guidelines.md.DddPdPom.lean.js +101 -0
  31. package/docs/docs/.vitepress/dist/assets/pages_how-it-works.md.OJGcGEXF.js +4 -0
  32. package/docs/docs/.vitepress/dist/assets/pages_how-it-works.md.OJGcGEXF.lean.js +4 -0
  33. package/docs/docs/.vitepress/dist/assets/pages_how-its-made.md.Vv9Z9TEi.js +1 -0
  34. package/docs/docs/.vitepress/dist/assets/pages_how-its-made.md.Vv9Z9TEi.lean.js +1 -0
  35. package/docs/docs/.vitepress/dist/assets/pages_introduction.md.DrDm-R8F.js +1 -0
  36. package/docs/docs/.vitepress/dist/assets/pages_introduction.md.DrDm-R8F.lean.js +1 -0
  37. package/docs/docs/.vitepress/dist/assets/pages_usage.md.zSOVjtFF.js +430 -0
  38. package/docs/docs/.vitepress/dist/assets/pages_usage.md.zSOVjtFF.lean.js +430 -0
  39. package/docs/docs/.vitepress/dist/assets/style.Fgx7OB_D.css +1 -0
  40. package/docs/docs/.vitepress/dist/hashmap.json +1 -1
  41. package/docs/docs/.vitepress/dist/index.html +7 -7
  42. package/docs/docs/.vitepress/dist/pages/advanced-usage.html +24 -0
  43. package/docs/docs/.vitepress/dist/pages/api.html +30 -0
  44. package/docs/docs/.vitepress/dist/pages/browse-code.html +24 -0
  45. package/docs/docs/.vitepress/dist/pages/getting-started.html +8 -8
  46. package/docs/docs/.vitepress/dist/pages/guidelines.html +125 -0
  47. package/docs/docs/.vitepress/dist/pages/how-it-works.html +10 -7
  48. package/docs/docs/.vitepress/dist/pages/how-its-made.html +24 -0
  49. package/docs/docs/.vitepress/dist/pages/introduction.html +7 -7
  50. package/docs/docs/.vitepress/dist/pages/usage.html +230 -74
  51. package/docs/docs/.vitepress/theme/index.js +5 -0
  52. package/docs/docs/.vitepress/theme/main.css +29 -0
  53. package/docs/docs/components/Button.vue +1 -1
  54. package/docs/docs/components/guidelines/CounterExternalRefsDetailed.vue +41 -0
  55. package/docs/docs/components/{examples → usage}/CounterBasic.vue +1 -1
  56. package/docs/docs/components/{examples → usage}/CounterComposables.vue +4 -5
  57. package/docs/docs/components/usage/CounterComposablesDestructuring.vue +46 -0
  58. package/docs/docs/components/usage/CounterComputeds.vue +25 -0
  59. package/docs/docs/components/usage/CounterComputedsDisabled.vue +32 -0
  60. package/docs/docs/components/{examples → usage}/CounterDefineExpose.vue +1 -1
  61. package/docs/docs/components/usage/CounterDefineExposeAdvanced.vue +25 -0
  62. package/docs/docs/components/{examples → usage}/CounterExternalRefs.vue +2 -2
  63. package/docs/docs/components/usage/CounterInsideComposables.vue +27 -0
  64. package/docs/docs/components/{examples → usage}/CounterInternalRefs.vue +1 -1
  65. package/docs/docs/components/usage/CounterLifecycleHooks.vue +22 -0
  66. package/docs/docs/components/usage/CounterWatch.vue +25 -0
  67. package/docs/docs/components/{examples → usage}/CounterWithProps.vue +1 -1
  68. package/docs/docs/components/{examples → usage}/CounterWithPropsAndEmits.vue +1 -1
  69. package/docs/docs/components/usage/functions/useMouse.ts +22 -0
  70. package/docs/docs/index.md +7 -6
  71. package/docs/docs/pages/advanced-usage.md +11 -0
  72. package/docs/docs/pages/api.md +106 -0
  73. package/docs/docs/pages/browse-code.md +18 -0
  74. package/docs/docs/pages/getting-started.md +14 -0
  75. package/docs/docs/pages/guidelines.md +128 -0
  76. package/docs/docs/pages/how-it-works.md +71 -0
  77. package/docs/docs/pages/how-its-made.md +32 -0
  78. package/docs/docs/pages/introduction.md +30 -21
  79. package/docs/docs/pages/usage.md +178 -50
  80. package/docs/package.json +2 -2
  81. package/package.json +4 -2
  82. package/src/__tests__/ivue.vitest.spec.ts +228 -132
  83. package/src/index.ts +1 -461
  84. package/src/ivue.ts +495 -0
  85. package/vite.config.ts +4 -0
  86. package/docs/.env +0 -1
  87. package/docs/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.xSEJiuF6.js +0 -1
  88. package/docs/docs/.vitepress/dist/assets/index.md.CktQD561.js +0 -1
  89. package/docs/docs/.vitepress/dist/assets/index.md.CktQD561.lean.js +0 -1
  90. package/docs/docs/.vitepress/dist/assets/pages_getting-started.md.COGFS1PH.js +0 -8
  91. package/docs/docs/.vitepress/dist/assets/pages_getting-started.md.COGFS1PH.lean.js +0 -1
  92. package/docs/docs/.vitepress/dist/assets/pages_how-it-works.md.DEn1nBQc.js +0 -1
  93. package/docs/docs/.vitepress/dist/assets/pages_how-it-works.md.DEn1nBQc.lean.js +0 -1
  94. package/docs/docs/.vitepress/dist/assets/pages_introduction.md.UHEKhynF.js +0 -1
  95. package/docs/docs/.vitepress/dist/assets/pages_introduction.md.UHEKhynF.lean.js +0 -1
  96. package/docs/docs/.vitepress/dist/assets/pages_usage.md.B75xObUi.js +0 -275
  97. package/docs/docs/.vitepress/dist/assets/pages_usage.md.B75xObUi.lean.js +0 -275
  98. package/docs/docs/.vitepress/dist/assets/style.DamVQLpl.css +0 -1
  99. package/docs/docs/components/examples/CounterComposablesDestructuring.vue +0 -66
  100. package/vitest.config.ts.timestamp-1723424289354-74cf8d2d72cb7.mjs +0 -162
  101. /package/docs/docs/components/{examples → usage}/CounterDefineExposeClass.ts +0 -0
@@ -0,0 +1,128 @@
1
+ <script setup lang="ts">
2
+ import CounterExternalRefsDetailed from '../components/guidelines/CounterExternalRefsDetailed.vue';
3
+ </script>
4
+
5
+ # Guidelines
6
+
7
+ ## Dos and Don'ts
8
+
9
+ ```ts
10
+ type UseMouse = UseComposable<typeof useMouse>;
11
+ /**
12
+ * Example of a properly defined ivue class.
13
+ */
14
+ class Counter {
15
+ /** ✅ Properly declared unwrapped composable. */
16
+ mouse: UseMouse;
17
+
18
+ constructor(public props: CounterProps, public emit: CounterEmit) {
19
+ this.mouse = useMouse() as unknown as UseMouse // ✅ Properly declared unwrapped composable.
20
+ }
21
+
22
+ /** ✅ Properly declared init function. */
23
+ init() {
24
+ /** ✅ Properly set lifecycle hook. */
25
+ onMounted(() => {
26
+ this.count = 4;
27
+ });
28
+
29
+ /** ✅ Properly set watch function */
30
+ watch(() => this.count, (newCount) => {
31
+ if (newCount === 5) {
32
+ alert('You reached the count of ' + newCount + '!');
33
+ }
34
+ })
35
+ }
36
+ /**
37
+ * Use ref() for the property and cast it to number
38
+ * because refs auto-unwrap inside reactive().
39
+ */
40
+ count = ref(0) as unknown as number; // ✅
41
+
42
+ /**
43
+ * Use ref() for the property and cast it to number
44
+ * because refs auto-unwrap inside reactive().
45
+ */
46
+ timesClicked = ref(0) as unknown as number; // ✅
47
+
48
+ /** ✅ Properly declared function (not arrow function). */
49
+ increment() {
50
+ this.count++;
51
+ }
52
+
53
+ /** ✅ Properly declared function (not arrow function). */
54
+ click() {
55
+ this.increment();
56
+ this.timesClicked++;
57
+ }
58
+
59
+ /**
60
+ * Do NOT use arrow functions, arrow functions are not extensible.
61
+ */
62
+ increment = () => this.count++ ❌
63
+
64
+ /** ✅ Properly declared computed getter. */
65
+ get doubleCount() {
66
+ return this.count * 2;
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### Use ref() for properties
72
+
73
+ `ivue` recommends all class properties to be defined as `ref()` to be able to interoperate with `defineExpose()`, if you simply pass reactive props which are not Refs through `defineExpose()`, they will lose reactivity. `ref()` refs just like computed refs get flattened into the `reactive()` object, so there is no need to worry about using `.value`. The `ref()` refs are necessary just internally for Vue 3 to know which refs to keep reactive.
74
+
75
+ ### Unwrap (de-Ref) the types
76
+
77
+ Next, we convert the types back to their normal types as if they have no reactivity at all, so `Ref<number>` is `number` in `ivue`, so rather than going in the direction of complexifying the types, we are going in the opposite direction towards simplification.
78
+
79
+ ### Use standard declaration syntax for functions
80
+
81
+ `ivue` recommends all class functions to be defined in plain full function style (not arrow functions), this allows all `ivue` classes to be extensible at any point. By using plain standard functions, it allows the developer to be able to override them at any time by simply extending the class.
82
+
83
+ ### Do not use arrow functions in class declarations
84
+
85
+ :::warning
86
+ Arrow functions break full extensibility of classes because they carry their own context at the point of declaration, so avoid using them inside of `ivue` classes.
87
+ :::
88
+
89
+ ## constructor() vs .init()
90
+
91
+ #### Use `constructor()` to assign properties of the class and cast Refs to Unwrapped bare types. <br />
92
+
93
+ #### Use `.init()` to declare reactive state functions like `watch`, `watchEffect`, and lifecycle hooks like `onMounted`, `onBeforeMount` etc, do assignments of reactive properties, since `init()` already has access to `reactive()` state through `this`.<br />
94
+
95
+ <hr />
96
+
97
+ Inside the `constructor()` method you still have access to non-reactive state, because when `constructor()` is initialized, it does NOT yet have access to the reactive properties of the class, since it was not yet converted to `reactive()` by `ivue`, so if you use the properties like Refs or ComputedRefs inside `constructor()` you would have to use them with the `.value`.
98
+
99
+ As a general rule, there is no need to manipulate the values in the `constructor()`, use constructor only for assigning the properties and casting the types of those assigned properties to the unwrapped (de-Refed) final state of the resulting `reactive()` object.
100
+
101
+ **Let's look at a `constructor()` vs `.init()` example:**
102
+
103
+ ::: code-group
104
+ <<< @/components/guidelines/CounterExternalRefsDetailed.vue{5,9-13,16-20,29,32,40 vue:line-numbers}
105
+ :::
106
+ :::details For this example we initialize the component like this:
107
+
108
+ ```vue
109
+ <template>
110
+ <CounterExternalRefsDetailed />
111
+ </template>
112
+ ```
113
+
114
+ :::
115
+
116
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
117
+
118
+ <CounterExternalRefsDetailed />
119
+
120
+ ## Unwrapping Refs
121
+
122
+ The key to working with `ivue` is understanding correctly the way Vue 3 does automatic Unwrapping of Refs when they are passed into the `reactive()` object. In that regard we are not relying on some magic `ivue` behavior but rather the default behavior of `reactive()` Vue 3 function.
123
+
124
+ To match that unwrapping behavior, our class needs to Unwrap (or de-Ref) the types of Composables, Refs, ComputedRefs, if they are being passed into the constructor, to get their raw basic types those Refs are pointing to, so that you can start operating in the `ivue` environment, where there is no need to worry about `.value`. This unwrapping should be mainly done inside the `constructor()` method.
125
+
126
+ ## Naming Conventions
127
+
128
+ To benefit from the full power of `ivue`, it is recommended to extract the classes into separate files. What has been an effective pattern is to name the classes and put them right beside components in the same folder that these classes are being used with. So if you have `CounterComponent.vue` component, it can have a class inside `CounterComponentClass.ts`, and you can store props, emits, and other runtime definitions inside `CounterComponentProps.ts`.
@@ -0,0 +1,71 @@
1
+ <script setup lang="ts">
2
+ import CounterBasic from '../components/usage/CounterBasic.vue'
3
+ </script>
4
+ # How it works?
5
+
6
+ ## What ivue is NOT?
7
+
8
+ To understand how ivue works and how it does it, it is important to understand what it does not do.
9
+
10
+ ::: info `ivue` is different from other class based libraries
11
+ &mdash; &nbsp;`ivue` does NOT inherit from a base class<br />
12
+ &mdash; &nbsp;`ivue` does NOT use decorators to achieve its objectives<br />
13
+ &mdash; &nbsp;`ivue` does NOT alter Vue 3 underlying behavior, but rather relies on it<br />
14
+ &mdash; &nbsp;`ivue` is NOT the same as class components (though you can build components with it)
15
+ :::
16
+
17
+ ## How it works?
18
+ ```ts
19
+ export function ivue<T extends AnyClass>(
20
+ className: T,
21
+ ...args: InferredArgs<T>
22
+ ): IVue<T>
23
+ ```
24
+ The main `ivue()` initializer function uses TypeScript to be able to infer and validate the constrcutor argument types of `AnyClass` and passes those arguments to the constructor of `AnyClass`.
25
+
26
+ `ivue` allows you to pass any number of arguments into the class `constructor(arg1, arg2, arg3, ...etc)`
27
+
28
+ `ivue()` initializer function returns an extended Vue 3 `reactive()` object in which getters and setters are internally converted to computeds and adds `.toRefs()` method to the created object. Computeds auto-unwrap themselves when they are accessed as a reactive object property, so the `.value` properties and computeds get flattened in the resulting object and do not require `.value` to be accessed.
29
+
30
+ `ivue` replicates native JavaScript / TypeScript class implementation by extending descriptors (getters and setters) up the whole prototype chain thus supporting classical inheritance.
31
+
32
+ `ivue` aims to be opaque and minimal, just doing the minimum to convert a class to a reactive object, leaving the rest to be implemented using Vue 3 Composition API inside an initializer function called `.init()`
33
+
34
+ ## Usage Recommendation
35
+ `ivue` recommends all class properties to be defined as `ref()` to be able to interoperate with `defineExpose()`, if you simply pass reactive props which are not Refs through `defineExpose()`, they will lose reactivity. `ref()` refs just like computed refs get flattened into the `reactive()` object, so there is no need to worry about using `.value`. The `ref()` refs are necessary just internally for Vue 3 to know which refs to keep reactive, and we just convert the types back to their normal types as if they have no reactivity at all, so `Ref<number>` is `number` in `ivue`, so rather than going in the direction of complexifying the types, we are going in the opposite direction towards simplification.
36
+
37
+ `ivue` recommends all class functions, getters and setters to be defined in plain full function style (not arrow functions), this allows all `ivue` classes to be extensible at any point. By using plain standard functions, getters and setters allows for any getter, setter, function or property to be overriden by extending this class. Arrow functions break full extensibility of classes, so avoid using them inside of classes.
38
+
39
+ See: [More Guidelines](/pages/guidelines.html)
40
+
41
+ ## Minimal API Surface Area
42
+
43
+ `ivue()` initializer function is the main API<br />
44
+ `.init()` method helps initialize the reactive state like `watch`, `onMount`, etc.<br />
45
+ `.toRefs()` method allows to interoperate with Vue 3 Composables<br />
46
+ Utility Types help to achieve the rest of `ivue` capabilities
47
+
48
+ :::details Click to see the whole latest `ivue` source code from github main branch below:
49
+ :::code-group
50
+ <<< ../../../src/index.ts{ts:line-numbers} [ivue.ts]
51
+ :::
52
+ Or [See on GitHub](https://github.com/infinite-system/ivue/blob/main/src/index.ts)
53
+
54
+ ## 100% Vue 3 Compatible
55
+ `.toRefs()` allows the object to be converted to Vue 3 native composable structure with full `.value`s, so it can interoperate with native composables if needed. `.toRefs()` is also often used to get refs for `v-bind()` in css styles.
56
+
57
+ ## 100% TypeScript Support
58
+
59
+ `ivue` is on the cutting edge of TypeScript and owes its capabilities to the latest developments in TypeScript.
60
+
61
+ `ivue` provides a set of utility types to make working with `Vue 3` even easier and more scalable.
62
+
63
+ ## 100% Unit Tested Architecture
64
+
65
+ At the current stage all of the code that is used to build `ivue` is 100% tested with 100% coverage, and aims to keep being at 100% always.
66
+
67
+ You can clone the project and run `yarn test` yourself and examine the tests.
68
+
69
+ ## Zero Dependencies
70
+
71
+ `ivue` has zero dependencies except Vue 3.
@@ -0,0 +1,32 @@
1
+
2
+ # How it's made
3
+
4
+ ## Original Inspiration
5
+
6
+ The original inspiration for `ivue` comes from `MobX` React state management library, where something similar is attempted to create a class based reactive observable architecture.
7
+
8
+ ## Epiphany
9
+
10
+ After building several ports from `MobX` state management library to `VueJS` to reactivity system I realized that Vue itself is far superior in its design and perfomance and can solve the same problem without relying on second hand-library, but for that my evolution of understanding of how JavaScript getters and setters work needed to happen.
11
+
12
+ And one lucky and sunny day driving back from work in an eureka moment of light it occured to me how to use Vue 3 computeds in place of getters in classes (Yes, apparently my brain does coding while driving a car).
13
+
14
+ `ivue` relies on this very simple discovery of how to elegantly convert getters into Vue 3 computeds.
15
+
16
+ ## Simplicity
17
+
18
+ After many iterations where I created a whole inversion of control library for `ivue`, using lots of different decorators and event Traits, I realized that simplicity is paramount to good architecture.
19
+
20
+ In that sweep of clarity, I got rid of 95% of the code that was just extra stuff and not the essence and left only `3` core functions: `ivue()`, `.init()`, `.toRefs()` only which are necessary to do everything `ivue` is set out to do.
21
+
22
+ Use Composition API composables inside `init()` function.
23
+
24
+ ## Minimalism
25
+
26
+ Thus `ivue` has minimal surface area of the API making it very robust and easy to test.
27
+ By default `ivue` does not rely on decorators, though you can use decorators if you wish to.
28
+
29
+ ## The Rest is Up To You
30
+ `ivue` is like a small mustard seed core for the big tree trunk of Class Based Reactive applications to be built around it, that's why the path of utter simplicity was chosen.
31
+ Everything else like an Inversion of Control (IOC) system, Traits, Mixins, Decorators can be built around the core `ivue` architecture and is upto the community of enthusiatic open source contributors, please share with us your vision of how you and all of can use `ivue` better.
32
+
@@ -1,53 +1,62 @@
1
1
  <script setup lang="ts">
2
2
  import Button from '../components/Button.vue'
3
3
  </script>
4
- # What is Infinite Vue (ivue) ?
4
+ # What is Infinite Vue?
5
5
 
6
- ## The Problem `ivue` Aims to Solve
6
+ ## The Problem
7
7
 
8
8
  With the development of React hooks and Vue following in its footsteps with introduction of Vue 3 Composition API, the ecosystem has moved away from Options API.
9
9
 
10
10
  While providing greater flexibility and composability the Composition API has its own downsides, one of them is having to use `.value` to refer to the reactive variables which makes the development process more clunky when the App reaches a certain size.
11
11
 
12
- As some of you may know, `reactvity-transform` macros were an attempt to mitigate those issues, which turned out to create even more issues, and was discontinued.
12
+ As you may know, `reactvity-transform` macros were an attempt to mitigate those issues, which turned out to create even more issues, and was discontinued.
13
13
 
14
- See: https://vuejs.org/guide/extras/reactivity-transform.html
14
+ See: [VueJs.org &ndash; Reactivity Transform](https://vuejs.org/guide/extras/reactivity-transform.html)
15
15
 
16
+ ## `ivue` is
17
+ <div style="padding-left:20px; font-size: 1.2rem; line-height: 2rem;">
18
+ &ndash;&nbsp; Simple like Options API<br />
19
+ &ndash;&nbsp; Flexible like Composition API<br />
20
+ &ndash;&nbsp; Extensible like TypeScript Classes API<br />
21
+ </div>
16
22
 
17
- ::: info IVUE UNIFIES COMPOSITION & OPTIONS API VIA CLASS BASED ARCHITECTURE
18
- &mdash;&nbsp; `ivue` mitigates the downsides of both Composition API and Options API, uses only their strengths and brings back Object Oriented Programming to allow the development of complex and scallable apps.
23
+ `ivue` is a powerful tool because it fully aligns itself with JavaScript / TypeScript Class API.
19
24
 
20
- &mdash;&nbsp; `ivue` is fully interoperable with Composition API and does not work against it but rather with it, so you can use all of ecosystems composables seamlessly.
25
+ `ivue` gives you a class based Composable capabilities with Inheritance and all the power of TypeScript Classes.
26
+
27
+ `ivue` mitigates the downsides of both Composition API and Options API, uses only their strengths and brings back Object Oriented Programming to allow the development of complex and scalable apps.
28
+
29
+ `ivue` is fully interoperable with Composition API and does not work against, but rather with it, so you can use all of ecosystems composables seamlessly.
30
+
31
+ `ivue` also offers a set of functions and utility types to make extensible & exportable props defaults, extensible emits and extensible slots possible.
21
32
 
22
- &mdash;&nbsp; `ivue` also offers a set of functions and utility types to make extensible & exportable props defaults, extensible emits and extensible slots possible.
23
- :::
24
33
 
25
- ## Classes are Back with Full Vue 3 Compatibility & Beyond
34
+ ## Classes in the Ecosystem
26
35
 
27
36
  With failed implementations of classes in React and also failed implementations using class components in Vue 2 / 3, the ecosystem decided that classes are bad and moved to pure procedural designs.
28
37
 
29
- While procedural programming has its strength, it also comes with its own weaknesses, like lack of inheritance and true composition.
38
+ While procedural programming has its strength, it also comes with its own weaknesses, like lack of inheritance, lack of `this` context, and thus lack of true composition.
30
39
 
31
40
  ::: info IVUE IS DIFFERENT
32
- &mdash; &nbsp;`ivue` does NOT inherit from a base class<br />
33
- &mdash; &nbsp;`ivue` does NOT use decorators to achieve its objectives<br />
34
- &mdash; &nbsp;`ivue` does NOT alter Vue 3 underlying behavior<br />
35
- &mdash; &nbsp;`ivue` is NOT the same as class components (though you can build components with it)<br />
41
+ &ndash; &nbsp;`ivue` does NOT inherit from a base class<br />
42
+ &ndash; &nbsp;`ivue` does NOT use decorators to achieve its objectives<br />
43
+ &ndash; &nbsp;`ivue` does NOT alter Vue 3 underlying behavior<br />
44
+ &ndash; &nbsp;`ivue` is NOT the same as class components (though you can build components with it)<br />
36
45
  :::
37
46
 
38
- ## Infinite Vue Achitecture
47
+ ## Infinite Vue Class Achitecture
39
48
 
40
- `ivue` mimicks native JavaScript / TypeScript class implementation by extending descriptors (getters and setters) up the whole prototype chain thus supporting classical inheritance.
49
+ `ivue` replicates native JavaScript / TypeScript class implementation by extending descriptors (getters and setters) up the whole prototype chain thus supporting classical inheritance.
41
50
 
42
- By using TypeScript we are able to infer the arguments of the main `ivue` initializer function and pass the arguments to the constructor.
51
+ By using TypeScript we are able to infer the arguments of the main `ivue()` initializer function and pass the arguments to the constructor.
43
52
 
44
- `ivue` initializer function returns a reactive object with getters converted to computeds and adds `.toRefs()` method to the object, `.toRefs()` allows the object to be converted to native composable structure, so it can interoperate as a composable if needed.
53
+ `ivue()` initializer function returns a reactive object with getters converted to computeds and adds `.toRefs()` method to the object, `.toRefs()` allows the object to be converted to native composable structure, so it can interoperate as a composable if needed.
45
54
 
46
- `ivue` aims to be opaque and minimal, just doing the minimum to convert a class to a reactive object, leaving the rest to be implemented using Vue 3 composition api inside an initializer function called `.init()`
55
+ `ivue` aims to be opaque and minimal, just doing the minimum to convert a class to a reactive object, leaving the rest to be implemented using Vue 3 Composition API inside an initializer function called `.init()`
47
56
 
48
57
  You can read more about `ivue` internal architecture in <Button href="/pages/how-it-works" label="How it works?" /> page.
49
58
 
50
59
  ## When to use Infinite Vue?
51
60
 
52
- When complexity of your app or components becomes very high using `ivue` can become a natural choice to deal with that complexity. Because `.value` is abstracted away in `ivue`, everything is simply a reactive object of unwrapped Refs.
61
+ When the complexity of your app or components becomes very high using `ivue` can become a natural choice to deal with that complexity. Because `.value` is abstracted away in `ivue`, everything is simply a reactive object of Refs.
53
62
 
@@ -1,32 +1,20 @@
1
- <style>
2
- .button {
3
- padding: 5px 10px;
4
- border-color: var(--vp-custom-block-details-border);
5
- color: var(--vp-custom-block-details-text);
6
- background-color: var(--vp-custom-block-details-bg);
7
- border-radius: 5px;
8
- margin-bottom: 2px;
9
- transition: 0.5s;
10
- }
11
- .button:hover {
12
- opacity: 0.8;
13
- }
14
- .button:active {
15
- opacity:0.9;
16
- }
17
- </style>
18
- <script lang="ts" setup>
1
+ <script setup lang="ts">
19
2
  import { ref } from 'vue';
20
3
 
21
- import CounterBasic from '../components/examples/CounterBasic.vue'
22
- import CounterWithProps from '../components/examples/CounterWithProps.vue'
23
- import CounterWithPropsAndEmits from '../components/examples/CounterWithPropsAndEmits.vue'
24
- import CounterDefineExpose from '../components/examples/CounterDefineExpose.vue'
25
- import CounterDefineExposeClass from '../components/examples/CounterDefineExposeClass'
26
- import CounterExternalRefs from '../components/examples/CounterExternalRefs.vue'
27
- import CounterInternalRefs from '../components/examples/CounterInternalRefs.vue'
28
- import CounterComposables from '../components/examples/CounterComposables.vue'
29
- import CounterComposablesDestructuring from '../components/examples/CounterComposablesDestructuring.vue'
4
+ import CounterBasic from '../components/usage/CounterBasic.vue'
5
+ import CounterWithProps from '../components/usage/CounterWithProps.vue'
6
+ import CounterWithPropsAndEmits from '../components/usage/CounterWithPropsAndEmits.vue'
7
+ import CounterDefineExpose from '../components/usage/CounterDefineExpose.vue'
8
+ import CounterDefineExposeClass from '../components/usage/CounterDefineExposeClass'
9
+ import CounterExternalRefs from '../components/usage/CounterExternalRefs.vue'
10
+ import CounterInternalRefs from '../components/usage/CounterInternalRefs.vue'
11
+ import CounterComposables from '../components/usage/CounterComposables.vue'
12
+ import CounterComposablesDestructuring from '../components/usage/CounterComposablesDestructuring.vue'
13
+ import CounterInsideComposables from '../components/usage/CounterInsideComposables.vue'
14
+ import CounterComputeds from '../components/usage/CounterComputeds.vue'
15
+ import CounterComputedsDisabled from '../components/usage/CounterComputedsDisabled.vue'
16
+ import CounterWatch from '../components/usage/CounterWatch.vue'
17
+ import CounterLifecycleHooks from '../components/usage/CounterLifecycleHooks.vue'
30
18
 
31
19
  // <For CounterWithPropsAndEmits example start>
32
20
  function onIncrement(value: number) {
@@ -56,44 +44,55 @@ Using ivue is very simple, but you need to understand a few principles. See the
56
44
 
57
45
  Classic Counter example built with `ivue`
58
46
  ::: code-group
59
- <<< @/components/examples/CounterBasic.vue{15 vue:line-numbers}
47
+ <<< @/components/usage/CounterBasic.vue{15 vue:line-numbers}
60
48
  :::
49
+
61
50
  :::details For this example we initialize the component like this:
51
+
52
+ ```vue
62
53
  <template>
63
- <CounterBasic />
54
+ <CounterBasic />
64
55
  </template>
56
+ ```
57
+
65
58
  :::
66
59
 
67
- ### Result:
60
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
68
61
 
69
62
  <CounterBasic />
70
63
  ::: warning NOTICE: JavaScript Class Caveat
71
- See `() => counter.increment()`. You cannot simply use `counter.increment` to refer to the method when it was defined as a object of a class, because that method would not know that it has to be bound to `counter`. You have to either use `() => counter.increment()` or `counter.increment.bind(counter)`, but the latter example is too verbose, so the preferred more readable way is to use an arrow function.
64
+ See `() => counter.increment()`. You cannot simply use `counter.increment` to refer to the method when it was defined as an object of a class, because that method would not know that it has to be bound to `counter`. You have to either use `() => counter.increment()` or `counter.increment.bind(counter)`, but the latter example is too verbose, so the preferred more readable way is to use an arrow function.
72
65
  :::
73
66
 
74
67
  ## Using Props
75
68
 
76
69
  See the highlighted sections related to props.
77
70
  ::: code-group
78
- <<< @/components/examples/CounterWithProps.vue{5-8,15-16,24 vue:line-numbers}
71
+ <<< @/components/usage/CounterWithProps.vue{5-8,11-12,24 vue:line-numbers}
79
72
  :::
73
+
80
74
  :::details For this example we initialize the component like this:
75
+
76
+ ```vue
81
77
  <template>
82
- <CounterWithProps :initial-count="5" />
78
+ <CounterWithProps :initial-count="5" />
83
79
  </template>
80
+ ```
81
+
84
82
  :::
85
83
 
86
- ### Result:
84
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
87
85
 
88
86
  <CounterWithProps :initial-count="5" />
89
87
 
90
88
  ## Using Emits
91
89
 
92
- See the highlighted sections related to `defineExpose`
90
+ See the highlighted sections related to using emits.
93
91
 
94
92
  ::: code-group
95
- <<< @/components/examples/CounterWithPropsAndEmits.vue{9-11,14,20,22,31 vue:line-numbers}
93
+ <<< @/components/usage/CounterWithPropsAndEmits.vue{9-11,14,17,23,31 vue:line-numbers}
96
94
  :::
95
+
97
96
  :::details For this example we initialize the component like this:
98
97
 
99
98
  ```vue
@@ -109,16 +108,16 @@ function onIncrement(value: number) {
109
108
 
110
109
  :::
111
110
 
112
- ### Result:
111
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
113
112
 
114
113
  <CounterWithPropsAndEmits :initial-count="5" @increment="onIncrement" />
115
114
 
116
115
  ## Using Refs
117
116
 
118
- ### Refs Defined Outside of ivue
117
+ ### Refs defined externally in the component outside of the class.
119
118
 
120
119
  ::: code-group
121
- <<< @/components/examples/CounterExternalRefs.vue{vue:line-numbers}
120
+ <<< @/components/usage/CounterExternalRefs.vue{5,8,12,16,24 vue:line-numbers}
122
121
  :::
123
122
  :::details For this example we initialize the component like this:
124
123
 
@@ -130,15 +129,16 @@ function onIncrement(value: number) {
130
129
 
131
130
  :::
132
131
 
133
- ### Result:
132
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
134
133
 
135
134
  <CounterExternalRefs />
136
135
 
137
- ### Refs Defined Inside of ivue class
136
+ ### Refs defined internally inside of the class.
138
137
 
139
138
  ::: code-group
140
- <<< @/components/examples/CounterInternalRefs.vue{vue:line-numbers}
139
+ <<< @/components/usage/CounterInternalRefs.vue{7,15,25 vue:line-numbers}
141
140
  :::
141
+
142
142
  :::details For this example we initialize the component like this:
143
143
 
144
144
  ```vue
@@ -149,18 +149,22 @@ function onIncrement(value: number) {
149
149
 
150
150
  :::
151
151
 
152
- ### Result:
152
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
153
153
 
154
154
  <CounterInternalRefs />
155
155
 
156
156
  ## Using Define Expose
157
157
 
158
+ ### Use class as interface for `defineExpose()`
158
159
  See the highlighted sections related to `defineExpose`.
160
+
159
161
  ::: code-group
160
- <<< @/components/examples/CounterDefineExpose.vue{8 vue:line-numbers}
161
- <<< @/components/examples/CounterDefineExposeClass.ts{ts:line-numbers}
162
+ <<< @/components/usage/CounterDefineExpose.vue{8 vue:line-numbers}
163
+ <<< @/components/usage/CounterDefineExposeClass.ts{ts:line-numbers}
162
164
  :::
165
+
163
166
  :::details For this example we initialize the component like this:
167
+
164
168
  ```vue
165
169
  <script setup lang="ts">
166
170
  const defineExposeRef = ref<CounterDefineExposeClass | null>(null);
@@ -183,43 +187,167 @@ function decrement() {
183
187
  <CounterDefineExpose />
184
188
  </template>
185
189
  ```
190
+
186
191
  :::
187
192
 
188
- ### Result:
193
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
189
194
 
190
195
  <button class="button" @click="increment">Increment via Component Ref from Parent Component</button><br />
191
196
  <button class="button" @click="decrement">Decrement via Component Ref from Parent Component</button>
192
197
  <CounterDefineExpose ref="defineExposeRef" />
193
198
 
199
+ ### Pick allowed interface properties for `defineExpose()`
200
+
201
+ ::: code-group
202
+ <<< @/components/usage/CounterDefineExposeAdvanced.vue{9,23 vue:line-numbers}
203
+ :::
204
+
194
205
  ## Using Composables
195
206
 
207
+ ### Assign a composable to a class property
208
+
196
209
  See the highlighted sections related to composable usage.
197
210
  ::: code-group
198
- <<< @/components/examples/CounterComposables.vue{4,11,19 vue:line-numbers}
211
+ <<< @/components/usage/CounterComposables.vue{4,11,19 vue:line-numbers}
199
212
  :::
213
+
200
214
  :::details For this example we initialize the component like this:
215
+
201
216
  ```vue
202
217
  <template>
203
218
  <CounterComposables />
204
219
  </template>
205
220
  ```
221
+
206
222
  :::
207
223
 
208
- ### Result:
224
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
225
+
209
226
  <CounterComposables />
210
227
 
211
228
  ### Destructuring composable into the class
229
+
212
230
  See the highlighted sections related to destructuring composable usage.
231
+
213
232
  ::: code-group
214
- <<< @/components/examples/CounterComposablesDestructuring.vue{4,11,19 vue:line-numbers}
233
+ <<< @/components/usage/CounterComposablesDestructuring.vue{4,10,20-21,23-24,27-32 vue:line-numbers}
234
+ <<< @/components/usage/functions/useMouse.ts{ts:line-numbers} [functions/useMouse.ts]
215
235
  :::
236
+
216
237
  :::details For this example we initialize the component like this:
238
+
217
239
  ```vue
218
240
  <template>
219
241
  <CounterComposablesDestructuring />
220
242
  </template>
221
243
  ```
244
+
222
245
  :::
223
246
 
224
- ### Result:
247
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
248
+
225
249
  <CounterComposablesDestructuring />
250
+
251
+ ## Using Inside Composables
252
+
253
+ See the highlighted sections related to using `ivue` inside a composable.
254
+
255
+ ::: code-group
256
+ <<< @/components/usage/CounterInsideComposables.vue{14 vue:line-numbers}
257
+ :::
258
+
259
+ :::details For this example we initialize the component like this:
260
+
261
+ ```vue
262
+ <template>
263
+ <CounterInsideComposables />
264
+ </template>
265
+ ```
266
+
267
+ :::
268
+
269
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
270
+
271
+ <CounterInsideComposables />
272
+
273
+
274
+ ## Using Computeds
275
+
276
+ ### Getters are computeds in `ivue` unless disabled.<br />
277
+ See the highlighted sections related to getters.
278
+
279
+ ::: code-group
280
+ <<< @/components/usage/CounterComputeds.vue{10,13,23,24 vue:line-numbers}
281
+ :::
282
+
283
+ :::details For this example we initialize the component like this:
284
+ ```vue
285
+ <template>
286
+ <CounterComputeds />
287
+ </template>
288
+ ```
289
+ :::
290
+
291
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
292
+ <CounterComputeds />
293
+
294
+ ### Disable computed behavior for certain getters in `ivue`.<br />
295
+ You can disable computed getters via `static ivue = { getter: false }`, see below:
296
+
297
+ ::: code-group
298
+ <<< @/components/usage/CounterComputedsDisabled.vue{10-12 vue:line-numbers}
299
+ :::
300
+
301
+ The result of this example is identical to the above.
302
+
303
+
304
+
305
+ ## Using Watch
306
+
307
+ To use `watch`, `watchEffect`, and other reactive functions, declare `.init()` method in the class.
308
+ See the highlighted sections related to using `init()` below:
309
+
310
+ ::: code-group
311
+ <<< @/components/usage/CounterWatch.vue{6-13 vue:line-numbers}
312
+ :::
313
+
314
+ :::details For this example we initialize the component like this:
315
+
316
+ ```vue
317
+ <template>
318
+ <CounterWatch />
319
+ </template>
320
+ ```
321
+
322
+ :::
323
+
324
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
325
+
326
+ <CounterWatch />
327
+
328
+
329
+
330
+ ## Using Lifecycle Hooks
331
+
332
+ To use `onMounted`, `onBeforeMount` and other lifecycle, declare `.init()` method in the class.
333
+ See the highlighted sections related to using `init()` below:
334
+
335
+ ::: tip NOTICE:
336
+ `init()` method can be declared as `async` if needed.
337
+ :::
338
+
339
+ ::: code-group
340
+ <<< @/components/usage/CounterLifecycleHooks.vue{7-9 vue:line-numbers}
341
+ :::
342
+
343
+ :::details For this example we initialize the component like this:
344
+
345
+ ```vue
346
+ <template>
347
+ <CounterLifecycleHooks />
348
+ </template>
349
+ ```
350
+ :::
351
+
352
+ <div style="font-size: 18px; font-weight: 500;">Result</div>
353
+ <CounterLifecycleHooks />