From 2525578ecb5a6fcdfa3be2cbdadb25f796dd0c44 Mon Sep 17 00:00:00 2001
From: wusaby-rush <19160044@su.edu.ye>
Date: Sat, 16 Jul 2022 14:18:17 +0000
Subject: [PATCH 1/3] Add petite-vue plugins support

---
 README.md  | 29 +++++++++++++++++++++++++++++
 src/app.ts |  5 +++++
 2 files changed, 34 insertions(+)

diff --git a/README.md b/README.md
index efa2241..0dd84fa 100644
--- a/README.md
+++ b/README.md
@@ -306,6 +306,35 @@ createApp({
 }).mount()
 ```
 
+### Use Plugins
+
+You can write custome directive then distrbute it as a pacage, then add it to create vue, like:
+
+```html
+<div v-scope="{counter: 0}" v-log="inside petite-vue scope">
+  <button @click="counter++">increase</button>
+</div>
+
+<script type="module">
+  import log from './log'
+  import { createApp } from 'peteite-vue'
+  createApp().use(log).mount()
+</script>
+```
+
+A plugin code similar to vue plugins code:
+
+```js
+// inside log.js plugin file
+export default {
+  install: (app, options) => {
+    app.directive('log', ({exp}) => {
+      console.log(exp)
+    })
+  }
+}
+```
+
 ## Examples
 
 Check out the [examples directory](https://github.com/vuejs/petite-vue/tree/main/examples).
diff --git a/src/app.ts b/src/app.ts
index 4a17bbc..e0e2107 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -42,6 +42,11 @@ export const createApp = (initialData?: any) => {
       }
     },
 
+    use(plugin: any, options = {}) {
+      plugin.install(this, options)
+      return this
+    },
+
     mount(el?: string | Element | null) {
       if (typeof el === 'string') {
         el = document.querySelector(el)

From b66a6dd7dd850bcc3c6f2929419f1e454dbdad8d Mon Sep 17 00:00:00 2001
From: wusaby-rush <rush@wusaby.me>
Date: Mon, 29 Aug 2022 03:03:01 +0300
Subject: [PATCH 2/3] Add `$root` refer to component root element

Some times like in dialogs we need access to root component from child nodes, also it is a way to access root element from `v-scope` . the next snippet from another PR to expose `$el` to scope, but this PR can solve the same problem also

```html
<textarea
  v-scope="{width: $root.offsetWidth, height: $root.offsetHeight}"
  @click="width = $el.offsetWidth; height = $el.offsetHeight;"
>
{{ width }} &times; {{ height }}
</textarea>
```
---
 README.md      | 11 ++++++++++-
 src/walk.ts    |  1 +
 tests/ref.html |  3 ++-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 0dd84fa..0661cd7 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,14 @@
   {{ count }}
   <button @click="count++">inc</button>
 </div>
+
+<!-- another example -->
+<textarea
+  v-scope="{width: $root.offsetWidth, height: $root.offsetHeight}"
+  @click="width = $el.offsetWidth; height = $el.offsetHeight;"
+>
+{{ width }} &times; {{ height }}
+</textarea>
 ```
 
 - Use `v-scope` to mark regions on the page that should be controlled by `petite-vue`.
@@ -346,10 +354,11 @@ Check out the [examples directory](https://github.com/vuejs/petite-vue/tree/main
 - `v-scope`
 - `v-effect`
 - `@vue:mounted` & `@vue:unmounted` events
+- `$root` refer to component root element
 
 ### Has Different Behavior
 
-- In expressions, `$el` points to the current element the directive is bound to (instead of component root element)
+- In expressions, `$el` points to the current element the directive is bound to (instead of component root element which accessed by `$root`)
 - `createApp()` accepts global state instead of a component
 - Components are simplified into object-returning functions
 - Custom directives have a different interface
diff --git a/src/walk.ts b/src/walk.ts
index f996461..0c8976d 100644
--- a/src/walk.ts
+++ b/src/walk.ts
@@ -40,6 +40,7 @@ export const walk = (node: Node, ctx: Context): ChildNode | null | void => {
     // v-scope
     if ((exp = checkAttr(el, 'v-scope')) || exp === '') {
       const scope = exp ? evaluate(ctx.scope, exp) : {}
+      scope.$root = el 
       ctx = createScopedContext(ctx, scope)
       if (scope.$template) {
         resolveTemplate(el, scope.$template)
diff --git a/tests/ref.html b/tests/ref.html
index ccb71fa..989587d 100644
--- a/tests/ref.html
+++ b/tests/ref.html
@@ -9,7 +9,8 @@
   v-scope="{ dynamicRef: 'x', show: true }"
   v-effect="console.log({ x: $refs.x, y: $refs.y, input: $refs.input })"
 >
-  <p>Accessing root el: id is {{ $refs.root.id }}</p>
+  <p>Accessing root el (with ref): id is {{ $refs.root.id }}</p>
+  <p>Accessing root el (with $root): id is {{ $refs.root.id }}</p>
 
   <input ref="input" />
   <span v-if="show" :ref="dynamicRef">Span with dynamic ref</span>

From 980daf577fd7e31b5a3239db10fcec18dbce2970 Mon Sep 17 00:00:00 2001
From: wusaby-rush <rush@wusaby.me>
Date: Mon, 29 Aug 2022 18:27:32 +0300
Subject: [PATCH 3/3] Change scope of ref with `v-scope`

---
 src/walk.ts    | 4 ++++
 tests/ref.html | 6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/walk.ts b/src/walk.ts
index 0c8976d..426406e 100644
--- a/src/walk.ts
+++ b/src/walk.ts
@@ -15,6 +15,7 @@ const modifierRE = /\.([\w-]+)/g
 export let inOnce = false
 
 export const walk = (node: Node, ctx: Context): ChildNode | null | void => {
+  const parentCtx = ctx
   const type = node.nodeType
   if (type === 1) {
     // Element
@@ -55,6 +56,9 @@ export const walk = (node: Node, ctx: Context): ChildNode | null | void => {
 
     // ref
     if ((exp = checkAttr(el, 'ref'))) {
+      if (ctx !== parentCtx) {
+      	applyDirective(el, ref, `"${exp}"`, parentCtx)
+      }
       applyDirective(el, ref, `"${exp}"`, ctx)
     }
 
diff --git a/tests/ref.html b/tests/ref.html
index 989587d..4885faa 100644
--- a/tests/ref.html
+++ b/tests/ref.html
@@ -7,7 +7,7 @@
   id="root"
   ref="root"
   v-scope="{ dynamicRef: 'x', show: true }"
-  v-effect="console.log({ x: $refs.x, y: $refs.y, input: $refs.input })"
+  v-effect="console.log({ x: $refs.x, y: $refs.y, input: $refs.input, modal: $refs.modal })"
 >
   <p>Accessing root el (with ref): id is {{ $refs.root.id }}</p>
   <p>Accessing root el (with $root): id is {{ $refs.root.id }}</p>
@@ -20,10 +20,10 @@
   </button>
   <button @click="show = !show">toggle</button>
 
-  <div v-scope>
+  <div id="modal" ref="modal" v-scope>
     <p ref="x">nested scope ref</p>
     <button
-      @click="console.log({ x: $refs.x, y: $refs.y, input: $refs.input })"
+      @click="console.log({ x: $refs.x, y: $refs.y, input: $refs.input, modal: $refs.modal })"
     >
       log nested scope refs
     </button>