mdk-skills 2.2.2 → 2.2.3

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 (187) hide show
  1. package/.claude/.install.log +9 -40
  2. package/.claude/backups/20260510.151953/.install.log +1 -0
  3. package/package.json +1 -1
  4. package/scripts/web-ui/server.js +8 -1
  5. package/.claude/backups/20260510.145547/.install.log +0 -18
  6. package/.claude/backups/20260510.145547/settings.json +0 -35
  7. package/.claude/backups/20260510.145547/skills/test1/.meta.json +0 -6
  8. package/.claude/backups/20260510.145547/skills/test2/.meta.json +0 -6
  9. package/.claude/backups/20260510.145651/.install.log +0 -19
  10. package/.claude/backups/20260510.145651/profiles.json +0 -67
  11. package/.claude/backups/20260510.145651/skills/frontend-code-review/.meta.json +0 -6
  12. package/.claude/backups/20260510.145651/skills/frontend-code-review/SKILL.md +0 -167
  13. package/.claude/backups/20260510.145651/skills/frontend-code-review/references/checklist.md +0 -298
  14. package/.claude/backups/20260510.145651/skills/frontend-design/.meta.json +0 -6
  15. package/.claude/backups/20260510.145651/skills/frontend-design/LICENSE.txt +0 -177
  16. package/.claude/backups/20260510.145651/skills/frontend-design/SKILL.md +0 -42
  17. package/.claude/backups/20260510.145651/skills/skill-creator/.meta.json +0 -6
  18. package/.claude/backups/20260510.145651/skills/skill-creator/SKILL.md +0 -356
  19. package/.claude/backups/20260510.145651/skills/skill-creator/references/output-patterns.md +0 -82
  20. package/.claude/backups/20260510.145651/skills/skill-creator/references/workflows.md +0 -28
  21. package/.claude/backups/20260510.145651/skills/skill-creator/scripts/init_skill.py +0 -303
  22. package/.claude/backups/20260510.145651/skills/skill-creator/scripts/package_skill.py +0 -110
  23. package/.claude/backups/20260510.145651/skills/skill-creator/scripts/quick_validate.py +0 -95
  24. package/.claude/backups/20260510.145651/skills/test1/.meta.json +0 -6
  25. package/.claude/backups/20260510.145651/skills/test2/.meta.json +0 -6
  26. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/.meta.json +0 -6
  27. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/SKILL.md +0 -228
  28. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/charts.csv +0 -26
  29. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/colors.csv +0 -97
  30. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/landing.csv +0 -31
  31. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/products.csv +0 -97
  32. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/prompts.csv +0 -24
  33. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  34. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  35. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  36. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  37. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  38. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  39. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  40. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  41. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  42. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  43. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/styles.csv +0 -59
  44. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/typography.csv +0 -58
  45. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  46. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/scripts/core.py +0 -238
  47. package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/scripts/search.py +0 -61
  48. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/.meta.json +0 -6
  49. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/SKILL.md +0 -26
  50. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
  51. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
  52. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
  53. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
  54. package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
  55. package/.claude/backups/20260510.145651/skills/vue/.meta.json +0 -6
  56. package/.claude/backups/20260510.145651/skills/vue/SKILL.md +0 -103
  57. package/.claude/backups/20260510.145651/skills/vue/references/components.md +0 -323
  58. package/.claude/backups/20260510.145651/skills/vue/references/composables.md +0 -358
  59. package/.claude/backups/20260510.145651/skills/vue/references/directives.md +0 -225
  60. package/.claude/backups/20260510.145651/skills/vue/references/gotchas.md +0 -438
  61. package/.claude/backups/20260510.145651/skills/vue/references/provide-inject.md +0 -174
  62. package/.claude/backups/20260510.145651/skills/vue/references/reactivity.md +0 -289
  63. package/.claude/backups/20260510.145651/skills/vue/references/router.md +0 -181
  64. package/.claude/backups/20260510.145651/skills/vue/references/testing.md +0 -294
  65. package/.claude/backups/20260510.145651/skills/vue/references/typescript.md +0 -172
  66. package/.claude/backups/20260510.145651/skills/vue/references/utils-client.md +0 -156
  67. package/.claude/backups/20260510.150310/.install.log +0 -30
  68. package/.claude/backups/20260510.150310/profiles.json +0 -67
  69. package/.claude/backups/20260510.150310/settings.json +0 -29
  70. package/.claude/backups/20260510.150310/skills/frontend-code-review/.meta.json +0 -6
  71. package/.claude/backups/20260510.150310/skills/frontend-code-review/SKILL.md +0 -167
  72. package/.claude/backups/20260510.150310/skills/frontend-code-review/references/checklist.md +0 -298
  73. package/.claude/backups/20260510.150310/skills/frontend-design/.meta.json +0 -6
  74. package/.claude/backups/20260510.150310/skills/frontend-design/LICENSE.txt +0 -177
  75. package/.claude/backups/20260510.150310/skills/frontend-design/SKILL.md +0 -42
  76. package/.claude/backups/20260510.150310/skills/skill-creator/.meta.json +0 -6
  77. package/.claude/backups/20260510.150310/skills/skill-creator/SKILL.md +0 -356
  78. package/.claude/backups/20260510.150310/skills/skill-creator/references/output-patterns.md +0 -82
  79. package/.claude/backups/20260510.150310/skills/skill-creator/references/workflows.md +0 -28
  80. package/.claude/backups/20260510.150310/skills/skill-creator/scripts/init_skill.py +0 -303
  81. package/.claude/backups/20260510.150310/skills/skill-creator/scripts/package_skill.py +0 -110
  82. package/.claude/backups/20260510.150310/skills/skill-creator/scripts/quick_validate.py +0 -95
  83. package/.claude/backups/20260510.150310/skills/test1/.meta.json +0 -6
  84. package/.claude/backups/20260510.150310/skills/test2/.meta.json +0 -6
  85. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/.meta.json +0 -6
  86. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/SKILL.md +0 -228
  87. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/charts.csv +0 -26
  88. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/colors.csv +0 -97
  89. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/landing.csv +0 -31
  90. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/products.csv +0 -97
  91. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/prompts.csv +0 -24
  92. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  93. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  94. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  95. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  96. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  97. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  98. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  99. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  100. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  101. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  102. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/styles.csv +0 -59
  103. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/typography.csv +0 -58
  104. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  105. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/scripts/core.py +0 -238
  106. package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/scripts/search.py +0 -61
  107. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/.meta.json +0 -6
  108. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/SKILL.md +0 -26
  109. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
  110. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
  111. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
  112. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
  113. package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
  114. package/.claude/backups/20260510.150310/skills/vue/.meta.json +0 -6
  115. package/.claude/backups/20260510.150310/skills/vue/SKILL.md +0 -103
  116. package/.claude/backups/20260510.150310/skills/vue/references/components.md +0 -323
  117. package/.claude/backups/20260510.150310/skills/vue/references/composables.md +0 -358
  118. package/.claude/backups/20260510.150310/skills/vue/references/directives.md +0 -225
  119. package/.claude/backups/20260510.150310/skills/vue/references/gotchas.md +0 -438
  120. package/.claude/backups/20260510.150310/skills/vue/references/provide-inject.md +0 -174
  121. package/.claude/backups/20260510.150310/skills/vue/references/reactivity.md +0 -289
  122. package/.claude/backups/20260510.150310/skills/vue/references/router.md +0 -181
  123. package/.claude/backups/20260510.150310/skills/vue/references/testing.md +0 -294
  124. package/.claude/backups/20260510.150310/skills/vue/references/typescript.md +0 -172
  125. package/.claude/backups/20260510.150310/skills/vue/references/utils-client.md +0 -156
  126. package/.claude/backups/CLAUDE.md.20260510.145155 +0 -131
  127. package/.claude/backups/CLAUDE.md.20260510.145651 +0 -131
  128. package/.claude/backups/CLAUDE.md.20260510.150310 +0 -131
  129. package/.claude/skills/test1/.meta.json +0 -6
  130. package/.claude/skills/test2/.meta.json +0 -6
  131. /package/.claude/backups/{20260510.145547 → 20260510.151953}/profiles.json +0 -0
  132. /package/.claude/backups/{20260510.145651 → 20260510.151953}/settings.json +0 -0
  133. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/.meta.json +0 -0
  134. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/SKILL.md +0 -0
  135. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/references/checklist.md +0 -0
  136. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/.meta.json +0 -0
  137. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/LICENSE.txt +0 -0
  138. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/SKILL.md +0 -0
  139. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/.meta.json +0 -0
  140. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/SKILL.md +0 -0
  141. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/references/output-patterns.md +0 -0
  142. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/references/workflows.md +0 -0
  143. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/init_skill.py +0 -0
  144. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/package_skill.py +0 -0
  145. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/quick_validate.py +0 -0
  146. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/.meta.json +0 -0
  147. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/SKILL.md +0 -0
  148. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/charts.csv +0 -0
  149. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/colors.csv +0 -0
  150. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/landing.csv +0 -0
  151. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/products.csv +0 -0
  152. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/prompts.csv +0 -0
  153. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -0
  154. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -0
  155. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -0
  156. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -0
  157. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -0
  158. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -0
  159. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/react.csv +0 -0
  160. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -0
  161. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -0
  162. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -0
  163. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/styles.csv +0 -0
  164. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/typography.csv +0 -0
  165. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -0
  166. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/scripts/core.py +0 -0
  167. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/scripts/search.py +0 -0
  168. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/.meta.json +0 -0
  169. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/SKILL.md +0 -0
  170. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -0
  171. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -0
  172. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/service-layer.md +0 -0
  173. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -0
  174. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/use-loading.md +0 -0
  175. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/.meta.json +0 -0
  176. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/SKILL.md +0 -0
  177. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/components.md +0 -0
  178. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/composables.md +0 -0
  179. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/directives.md +0 -0
  180. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/gotchas.md +0 -0
  181. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/provide-inject.md +0 -0
  182. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/reactivity.md +0 -0
  183. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/router.md +0 -0
  184. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/testing.md +0 -0
  185. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/typescript.md +0 -0
  186. /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/utils-client.md +0 -0
  187. /package/.claude/backups/{CLAUDE.md.20260510.144501 → CLAUDE.md.20260510.151953} +0 -0
@@ -1,358 +0,0 @@
1
- # Vue Composables
2
-
3
- Reusable functions encapsulating stateful logic using Composition API.
4
-
5
- ## Core Rules
6
-
7
- 1. **VueUse first** - check [vueuse.org](https://vueuse.org) before writing custom
8
- 2. **No async composables** - lose lifecycle context when awaited in other composables
9
- 3. **Top-level only** - never call in event handlers, conditionals, or loops
10
- 4. **readonly() exports** - protect internal state from external mutation
11
- 5. **useState() for SSR** - use Nuxt's `useState()` not global refs
12
-
13
- ## Quick Reference
14
-
15
- | Pattern | Example |
16
- | --------- | ------------------------------------------------ |
17
- | Naming | `useAuth`, `useCounter`, `useDebounce` |
18
- | State | `const count = ref(0)` |
19
- | Computed | `const double = computed(() => count.value * 2)` |
20
- | Lifecycle | `onMounted(() => ...)`, `onUnmounted(() => ...)` |
21
- | Return | `return { count, increment }` |
22
-
23
- ## Structure
24
-
25
- ```ts
26
- // composables/useCounter.ts
27
- import { readonly, ref } from 'vue'
28
-
29
- export function useCounter(initialValue = 0) {
30
- const count = ref(initialValue)
31
-
32
- function increment() { count.value++ }
33
- function decrement() { count.value-- }
34
- function reset() { count.value = initialValue }
35
-
36
- return {
37
- count: readonly(count), // readonly if shouldn't be mutated
38
- increment,
39
- decrement,
40
- reset,
41
- }
42
- }
43
- ```
44
-
45
- ## Naming
46
-
47
- **Always prefix with `use`:** `useAuth`, `useLocalStorage`, `useDebounce`
48
-
49
- **File = function:** `useAuth.ts` exports `useAuth`
50
-
51
- ## Best Practices
52
-
53
- **Do:**
54
-
55
- - Return object with named properties (destructuring-friendly)
56
- - Accept options object for configuration
57
- - Use `readonly()` for state that shouldn't mutate
58
- - Handle cleanup (`onUnmounted`, `onScopeDispose`)
59
- - Add JSDoc for complex functions
60
-
61
- ## Lifecycle
62
-
63
- Hooks execute in component context:
64
-
65
- ```ts
66
- export function useEventListener(target: EventTarget, event: string, handler: Function) {
67
- onMounted(() => target.addEventListener(event, handler))
68
- onUnmounted(() => target.removeEventListener(event, handler))
69
- }
70
- ```
71
-
72
- **Watcher cleanup (Vue 3.5+):**
73
-
74
- ```ts
75
- import { watch, onWatcherCleanup } from 'vue'
76
-
77
- export function usePolling(url: Ref<string>) {
78
- watch(url, (newUrl) => {
79
- const interval = setInterval(() => {
80
- fetch(newUrl).then(/* ... */)
81
- }, 1000)
82
-
83
- // Cleanup when watcher re-runs or stops
84
- onWatcherCleanup(() => {
85
- clearInterval(interval)
86
- })
87
- })
88
- }
89
- ```
90
-
91
- **Benefits of `onWatcherCleanup()`:**
92
-
93
- - Cleaner than returning cleanup functions
94
- - Works with async watchers
95
- - Can be called multiple times in same watcher
96
-
97
- ## Async Pattern
98
-
99
- ```ts
100
- export function useAsyncData<T>(fetcher: () => Promise<T>) {
101
- const data = ref<T | null>(null)
102
- const error = ref<Error | null>(null)
103
- const loading = ref(false)
104
-
105
- async function execute() {
106
- loading.value = true
107
- error.value = null
108
- try {
109
- data.value = await fetcher()
110
- }
111
- catch (e) {
112
- error.value = e as Error
113
- }
114
- finally {
115
- loading.value = false
116
- }
117
- }
118
-
119
- execute()
120
- return { data, error, loading, refetch: execute }
121
- }
122
- ```
123
-
124
- **Data fetching:** Prefer Pinia Colada queries over custom composables.
125
-
126
- ## VueUse
127
-
128
- > For VueUse composable reference, use the `vueuse` skill.
129
-
130
- Check VueUse before writing custom composables - most patterns already implemented.
131
-
132
- > **For Nuxt-specific composables** (useFetch, useRequestURL): see `nuxt` skill nuxt-composables.md
133
-
134
- ## Advanced Patterns
135
-
136
- ### Singleton Composable
137
-
138
- Share state across all components using the same composable:
139
-
140
- ```ts
141
- import { createSharedComposable } from '@vueuse/core'
142
-
143
- function useMapControlsBase() {
144
- const mapInstance = ref<Map | null>(null)
145
- const flyTo = (coords: [number, number]) => mapInstance.value?.flyTo(coords)
146
- return { mapInstance, flyTo }
147
- }
148
-
149
- export const useMapControls = createSharedComposable(useMapControlsBase)
150
- ```
151
-
152
- ### Cancellable Fetch with AbortController
153
-
154
- ```ts
155
- export function useSearch() {
156
- let abortController: AbortController | null = null
157
-
158
- watch(query, async (newQuery) => {
159
- abortController?.abort()
160
- abortController = new AbortController()
161
-
162
- try {
163
- const data = await $fetch('/api/search', {
164
- query: { q: newQuery },
165
- signal: abortController.signal,
166
- })
167
- }
168
- catch (e) {
169
- if (e.name !== 'AbortError')
170
- throw e
171
- }
172
- })
173
- }
174
- ```
175
-
176
- ### Step-Based State Machine
177
-
178
- ```ts
179
- export function useSendFlow() {
180
- const step = ref<'input' | 'confirm' | 'success'>('input')
181
- const amount = ref('')
182
-
183
- const next = () => {
184
- if (step.value === 'input')
185
- step.value = 'confirm'
186
- else if (step.value === 'confirm')
187
- step.value = 'success'
188
- }
189
-
190
- return { step, amount, next }
191
- }
192
- ```
193
-
194
- ### Client-Only Guards
195
-
196
- ```ts
197
- export function useUserLocation() {
198
- const location = ref<GeolocationPosition | null>(null)
199
-
200
- if (import.meta.client) {
201
- navigator.geolocation.getCurrentPosition(pos => location.value = pos)
202
- }
203
-
204
- return { location }
205
- }
206
- ```
207
-
208
- ### Custom Element Composables (Vue 3.5+)
209
-
210
- For custom element components, use built-in helpers:
211
-
212
- ```ts
213
- import { useHost, useShadowRoot } from 'vue'
214
-
215
- export function useCustomElement() {
216
- const host = useHost() // Host element reference
217
- const shadowRoot = useShadowRoot() // Shadow DOM root
218
-
219
- onMounted(() => {
220
- console.log('Host:', host)
221
- console.log('Shadow:', shadowRoot)
222
- })
223
-
224
- return { host, shadowRoot }
225
- }
226
- ```
227
-
228
- **Available in:**
229
-
230
- - Components using `<script setup>` in custom elements
231
- - Access via `this.$host` in Options API
232
-
233
- ### Auto-Save with Debounce
234
-
235
- ```ts
236
- export function useAutoSave(content: Ref<string>) {
237
- const hasChanges = ref(false)
238
-
239
- const save = useDebounceFn(async () => {
240
- if (!hasChanges.value)
241
- return
242
- await $fetch('/api/save', { method: 'POST', body: { content: content.value } })
243
- hasChanges.value = false
244
- }, 1000)
245
-
246
- watch(content, () => {
247
- hasChanges.value = true
248
- save()
249
- })
250
-
251
- return { hasChanges }
252
- }
253
- ```
254
-
255
- ### Tagged Logger
256
-
257
- ```ts
258
- import { consola } from 'consola'
259
-
260
- export function useSearch() {
261
- const logger = consola.withTag('search')
262
-
263
- watch(query, (q) => {
264
- logger.info('Query changed:', q)
265
- })
266
- }
267
- ```
268
-
269
- ## Reactivity Gotchas
270
-
271
- ### Ref Unwrapping in Reactive
272
-
273
- Refs auto-unwrap in `reactive()` objects but **NOT** in arrays, Maps, or Sets:
274
-
275
- ```ts
276
- // ✅ Object - auto unwraps
277
- const state = reactive({ count: ref(0) })
278
- state.count++ // No .value needed
279
-
280
- // ❌ Array - NO unwrapping
281
- const arr = reactive([ref(1)])
282
- arr[0].value // Need .value!
283
-
284
- // ❌ Map/Set - NO unwrapping
285
- const map = reactive(new Map([['key', ref(1)]]))
286
- map.get('key').value // Need .value!
287
- ```
288
-
289
- ### watchEffect Conditional Tracking
290
-
291
- Dependencies inside conditional branches are **not tracked** when condition is false:
292
-
293
- ```ts
294
- // ❌ Wrong - dep not tracked when condition false
295
- watchEffect(() => {
296
- if (condition.value) {
297
- console.log(dep.value) // Only tracked when condition=true
298
- }
299
- })
300
-
301
- // ✅ Correct - use explicit watch for conditional deps
302
- watch([condition, dep], ([cond, d]) => {
303
- if (cond) console.log(d)
304
- })
305
- ```
306
-
307
- ### Cleanup Patterns
308
-
309
- **For keep-alive components** - use `onDeactivated`:
310
-
311
- ```ts
312
- export function usePolling() {
313
- let interval: NodeJS.Timeout
314
-
315
- onMounted(() => { interval = setInterval(poll, 5000) })
316
- onUnmounted(() => clearInterval(interval))
317
- onDeactivated(() => clearInterval(interval)) // Pause when deactivated
318
- onActivated(() => { interval = setInterval(poll, 5000) }) // Resume
319
- }
320
- ```
321
-
322
- **For scope-aware cleanup** - use `tryOnScopeDispose` from VueUse:
323
-
324
- ```ts
325
- import { tryOnScopeDispose } from '@vueuse/core'
326
-
327
- export function useEventSource(url: string) {
328
- const source = new EventSource(url)
329
-
330
- // Cleans up when effect scope disposes (component unmount, watcher stop)
331
- tryOnScopeDispose(() => source.close())
332
-
333
- return { source }
334
- }
335
- ```
336
-
337
- ## Common Mistakes
338
-
339
- **Not using `readonly()` for internal state:**
340
-
341
- ```ts
342
- // ❌ Wrong - exposes mutable ref
343
- return { count }
344
-
345
- // ✅ Correct - prevents external mutation
346
- return { count: readonly(count) }
347
- ```
348
-
349
- **Missing cleanup:**
350
-
351
- ```ts
352
- // ❌ Wrong - listener never removed
353
- onMounted(() => target.addEventListener('click', handler))
354
-
355
- // ✅ Correct - cleanup on unmount
356
- onMounted(() => target.addEventListener('click', handler))
357
- onUnmounted(() => target.removeEventListener('click', handler))
358
- ```
@@ -1,225 +0,0 @@
1
- ---
2
- name: Custom Directives
3
- description: Create reusable directives for low-level DOM manipulation
4
- ---
5
-
6
- # Custom Directives
7
-
8
- Custom directives provide low-level DOM access for reusable behavior.
9
-
10
- ## When to Use
11
-
12
- Use custom directives when:
13
-
14
- - You need direct DOM manipulation
15
- - The behavior can't be achieved with components or composables
16
- - You need to apply behavior to native elements
17
-
18
- ## Basic Example
19
-
20
- ```vue
21
- <script setup lang="ts">
22
- // v-focus directive
23
- const vFocus = {
24
- mounted: (el: HTMLElement) => el.focus()
25
- }
26
- </script>
27
-
28
- <template>
29
- <input v-focus />
30
- </template>
31
- ```
32
-
33
- ## Directive Hooks
34
-
35
- ```ts
36
- const myDirective = {
37
- // Before element attributes/listeners are applied
38
- created(el, binding, vnode) {},
39
-
40
- // Before element is inserted into DOM
41
- beforeMount(el, binding, vnode) {},
42
-
43
- // After element and children are mounted
44
- mounted(el, binding, vnode) {},
45
-
46
- // Before parent component updates
47
- beforeUpdate(el, binding, vnode, prevVnode) {},
48
-
49
- // After parent component updates
50
- updated(el, binding, vnode, prevVnode) {},
51
-
52
- // Before parent component unmounts
53
- beforeUnmount(el, binding, vnode) {},
54
-
55
- // After parent component unmounts
56
- unmounted(el, binding, vnode) {}
57
- }
58
- ```
59
-
60
- ## Hook Arguments
61
-
62
- ```ts
63
- interface DirectiveBinding<T = any> {
64
- value: T // v-my-dir="value"
65
- oldValue: T // Previous value (beforeUpdate/updated only)
66
- arg?: string // v-my-dir:arg
67
- modifiers: Record<string, boolean> // v-my-dir.foo.bar → { foo: true, bar: true }
68
- instance: ComponentPublicInstance // Component using the directive
69
- dir: ObjectDirective // Directive definition object
70
- }
71
- ```
72
-
73
- Example usage:
74
-
75
- ```vue-html
76
- <div v-example:foo.bar="baz">
77
- ```
78
-
79
- ```ts
80
- // binding object:
81
- {
82
- arg: 'foo',
83
- modifiers: { bar: true },
84
- value: /* value of baz */,
85
- oldValue: /* previous value */
86
- }
87
- ```
88
-
89
- ## Function Shorthand
90
-
91
- When you only need `mounted` and `updated` with same behavior:
92
-
93
- ```ts
94
- // Full form
95
- const vColor = {
96
- mounted(el, binding) {
97
- el.style.color = binding.value
98
- },
99
- updated(el, binding) {
100
- el.style.color = binding.value
101
- }
102
- }
103
-
104
- // Shorthand (same behavior)
105
- const vColor = (el: HTMLElement, binding: DirectiveBinding<string>) => {
106
- el.style.color = binding.value
107
- }
108
- ```
109
-
110
- ## Global Registration
111
-
112
- ```ts
113
- // main.ts
114
- const app = createApp(App)
115
-
116
- app.directive('focus', {
117
- mounted: (el) => el.focus()
118
- })
119
-
120
- // Shorthand
121
- app.directive('color', (el, binding) => {
122
- el.style.color = binding.value
123
- })
124
- ```
125
-
126
- ## Object Literals
127
-
128
- Pass multiple values:
129
-
130
- ```vue-html
131
- <div v-demo="{ color: 'white', text: 'hello' }">
132
- ```
133
-
134
- ```ts
135
- const vDemo = (el: HTMLElement, binding: DirectiveBinding<{ color: string; text: string }>) => {
136
- console.log(binding.value.color) // 'white'
137
- console.log(binding.value.text) // 'hello'
138
- }
139
- ```
140
-
141
- ## Dynamic Arguments
142
-
143
- ```vue-html
144
- <div v-my-directive:[dynamicArg]="value">
145
- ```
146
-
147
- ## Practical Examples
148
-
149
- ### v-click-outside
150
-
151
- ```ts
152
- const vClickOutside = {
153
- mounted(el: HTMLElement, binding: DirectiveBinding<() => void>) {
154
- el._clickOutside = (event: MouseEvent) => {
155
- if (!el.contains(event.target as Node)) {
156
- binding.value()
157
- }
158
- }
159
- document.addEventListener('click', el._clickOutside)
160
- },
161
- unmounted(el: HTMLElement) {
162
- document.removeEventListener('click', el._clickOutside)
163
- }
164
- }
165
- ```
166
-
167
- ### v-tooltip
168
-
169
- ```ts
170
- const vTooltip = {
171
- mounted(el: HTMLElement, binding: DirectiveBinding<string>) {
172
- el.setAttribute('title', binding.value)
173
- },
174
- updated(el: HTMLElement, binding: DirectiveBinding<string>) {
175
- el.setAttribute('title', binding.value)
176
- }
177
- }
178
- ```
179
-
180
- ### v-permission
181
-
182
- ```ts
183
- const vPermission = {
184
- mounted(el: HTMLElement, binding: DirectiveBinding<string>) {
185
- if (!hasPermission(binding.value)) {
186
- el.parentNode?.removeChild(el)
187
- }
188
- }
189
- }
190
- ```
191
-
192
- ## TypeScript: Global Directives
193
-
194
- ```ts
195
- // directives/highlight.ts
196
- import type { Directive } from 'vue'
197
-
198
- export type HighlightDirective = Directive<HTMLElement, string>
199
-
200
- declare module 'vue' {
201
- export interface ComponentCustomProperties {
202
- vHighlight: HighlightDirective
203
- }
204
- }
205
-
206
- export default {
207
- mounted: (el, binding) => {
208
- el.style.backgroundColor = binding.value
209
- }
210
- } satisfies HighlightDirective
211
- ```
212
-
213
- ## Usage on Components
214
-
215
- ⚠️ **Not recommended** - directives apply to root element, which can be unpredictable with multi-root components.
216
-
217
- ```vue-html
218
- <!-- Applies to MyComponent's root element -->
219
- <MyComponent v-my-directive />
220
- ```
221
-
222
- <!--
223
- Source references:
224
- - https://vuejs.org/guide/reusability/custom-directives.html
225
- -->