directix 1.11.0 → 2.1.0

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/README.md CHANGED
@@ -8,12 +8,13 @@
8
8
 
9
9
  **English** | **[中文文档](README_CN.md)**
10
10
 
11
- A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3.
11
+ A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3, with Web Components support.
12
12
 
13
13
  ## Features
14
14
 
15
15
  - 🎯 **Comprehensive** - 57 commonly used directives and 57 composables
16
- - 🔄 **Vue 2/3 Compatible** - Single codebase supports both Vue 2 and Vue 3
16
+ - 🔄 **Vue 2/3 Compatible** - Single codebase supporting both Vue 2.6+ and Vue 3.0+
17
+ - 🧩 **Web Components** - Use directives with Custom Elements / Web Components
17
18
  - 📦 **Tree-shakable** - Import only what you need
18
19
  - 🔒 **TypeScript** - Full TypeScript support with type definitions
19
20
  - 🚀 **SSR Friendly** - Multiple directives support SSR out of the box
@@ -24,16 +25,65 @@ A comprehensive, easy-to-use, and high-performance Vue custom directives library
24
25
  - 🌐 **i18n Support** - Built-in internationalization with Chinese, English, and Japanese translations
25
26
  - 🔌 **Plugin System** - Extensible plugin architecture for community contributions
26
27
 
27
- ## What's New in v1.10.0
28
+ ## What's New in v2.1.0
28
29
 
29
- ### Vue 3 Optimization Preview
30
+ ### Enhanced Web Components Support
30
31
 
31
- Vue 3-specific optimizations leveraging the reactive system for better performance.
32
+ v2.1.0 significantly enhances Web Components support with Shadow DOM, SSR safety, lifecycle hooks, and more:
33
+
34
+ ```typescript
35
+ import {
36
+ vLazy,
37
+ defineCustomElementDirective,
38
+ createSSRSafeCustomElement,
39
+ hydrateCustomElements
40
+ } from 'directix'
41
+
42
+ // Define with lifecycle hooks and styles
43
+ defineCustomElementDirective({
44
+ name: 'lazy-img',
45
+ directive: vLazy,
46
+ shadow: true,
47
+ styles: ':host { display: block; }',
48
+ lifecycle: {
49
+ onConnect: (el) => console.log('Connected', el),
50
+ onDisconnect: (el) => console.log('Disconnected', el),
51
+ },
52
+ })
53
+
54
+ // SSR-safe custom elements
55
+ const LazyImage = createSSRSafeCustomElement('lazy-img', vLazy, {
56
+ shadow: true,
57
+ styles: ':host { display: block; }',
58
+ })
59
+
60
+ // SSR render
61
+ const html = LazyImage.ssrRender({ src: 'image.jpg' })
62
+
63
+ // Client hydration
64
+ hydrateCustomElements(document.body)
65
+ ```
66
+
67
+ ### New Web Components APIs
68
+
69
+ | API | Description |
70
+ |-----|-------------|
71
+ | `CustomElementLifecycleHooks` | Lifecycle hooks interface (onConnect, onDisconnect, onAdopt, onAttributeChange) |
72
+ | `SSRSafeCustomElement` | SSR-safe custom element type |
73
+ | `isCustomElementDefined(name)` | Check if a custom element is already defined |
74
+ | `whenCustomElementDefined(name)` | Async wait for custom element definition |
75
+ | `getRegisteredCustomElements()` | Get all registered custom element names |
76
+ | `hydrateCustomElements(root)` | Hydrate custom elements on client (SSR support) |
77
+ | `createSSRSafeCustomElement()` | Create SSR-safe custom elements with declarative Shadow DOM |
78
+
79
+ ### Vue 3 Conditional Optimizations
80
+
81
+ When using Vue 3, Directix automatically applies performance optimizations:
32
82
 
33
83
  ```typescript
34
84
  import { useLazyOptimized, useSuspenseDirective, teleportContent } from 'directix'
35
85
 
36
- // Optimized lazy loading with shallowRef
86
+ // Optimized lazy loading with shallowRef (Vue 3 only)
37
87
  const { state, observe } = useLazyOptimized({
38
88
  onLoad: (entry) => console.log('Visible!')
39
89
  })
@@ -47,6 +97,10 @@ const { state, load } = useSuspenseDirective({
47
97
  teleportContent(element, { to: '#modal-container' })
48
98
  ```
49
99
 
100
+ ### Vue 2 Support Maintained
101
+
102
+ **v2.0.0 will maintain full Vue 2 compatibility** - all v1.x code continues to work without modifications. We are committed to supporting both Vue 2 and Vue 3.
103
+
50
104
  ### Mobile Optimization
51
105
 
52
106
  Enhanced touch gestures with haptic feedback and PWA support.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * directix v1.11.0
3
- * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
2
+ * directix v2.1.0
3
+ * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3, with Web Components support
4
4
  * (c) 2021-present saqqdy <https://github.com/saqqdy>
5
5
  * Released under the MIT License.
6
6
  */
@@ -79,8 +79,8 @@ var __async = (__this, __arguments, generator) => {
79
79
  });
80
80
  };
81
81
  /*!
82
- * directix v1.11.0
83
- * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
82
+ * directix v2.1.0
83
+ * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3, with Web Components support
84
84
  * (c) 2021-present saqqdy <https://github.com/saqqdy>
85
85
  * Released under the MIT License.
86
86
  */
@@ -99,7 +99,7 @@ function createVue2Directive(hooks) {
99
99
  },
100
100
  inserted(el, binding, vnode) {
101
101
  if (hooks.mounted) {
102
- hooks.mounted(el, normalizeBinding$1(binding), vnode);
102
+ hooks.mounted(el, normalizeBinding$2(binding), vnode);
103
103
  }
104
104
  },
105
105
  update(el, binding, vnode, oldVnode) {
@@ -107,9 +107,9 @@ function createVue2Directive(hooks) {
107
107
  if (hooks.updated) {
108
108
  hooks.updated(
109
109
  el,
110
- normalizeBinding$1(binding),
110
+ normalizeBinding$2(binding),
111
111
  vnode,
112
- normalizeBinding$1(__spreadProps(__spreadValues({}, binding), { value: binding.oldValue })),
112
+ normalizeBinding$2(__spreadProps(__spreadValues({}, binding), { value: binding.oldValue })),
113
113
  oldVnode
114
114
  );
115
115
  }
@@ -122,7 +122,7 @@ function createVue2Directive(hooks) {
122
122
  },
123
123
  unbind(el, binding, vnode) {
124
124
  if (hooks.unmounted) {
125
- hooks.unmounted(el, normalizeBinding$1(binding), vnode);
125
+ hooks.unmounted(el, normalizeBinding$2(binding), vnode);
126
126
  }
127
127
  const state2 = el.__directix_state__;
128
128
  if (state2 == null ? void 0 : state2.cleanup) {
@@ -133,7 +133,7 @@ function createVue2Directive(hooks) {
133
133
  };
134
134
  return directive;
135
135
  }
136
- function normalizeBinding$1(binding) {
136
+ function normalizeBinding$2(binding) {
137
137
  var _a2;
138
138
  return {
139
139
  value: binding.value,
@@ -150,20 +150,20 @@ function addCleanup$1(el, fn) {
150
150
  }
151
151
  }
152
152
  function createVue3Directive(hooks) {
153
- const directive = {
153
+ return {
154
154
  created(el, binding, vnode) {
155
- const state2 = {
156
- value: binding.value,
155
+ const state2 = vue.shallowReactive({
156
+ value: binding.value != null ? vue.markRaw(binding.value) : binding.value,
157
157
  vnode,
158
158
  cleanup: []
159
- };
159
+ });
160
160
  el.__directix_state__ = state2;
161
161
  },
162
162
  beforeMount(_el, _binding, _vnode) {
163
163
  },
164
164
  mounted(el, binding, vnode) {
165
165
  if (hooks.mounted) {
166
- hooks.mounted(el, normalizeBindingVue3(binding), vnode);
166
+ hooks.mounted(el, normalizeBinding$1(binding), vnode);
167
167
  }
168
168
  },
169
169
  beforeUpdate(_el, _binding, _vnode, _prevVnode) {
@@ -173,14 +173,14 @@ function createVue3Directive(hooks) {
173
173
  if (hooks.updated) {
174
174
  hooks.updated(
175
175
  el,
176
- normalizeBindingVue3(binding),
176
+ normalizeBinding$1(binding),
177
177
  vnode,
178
- normalizeBindingVue3(__spreadProps(__spreadValues({}, binding), { value: binding.oldValue })),
178
+ normalizeBinding$1(__spreadProps(__spreadValues({}, binding), { value: binding.oldValue })),
179
179
  prevVnode
180
180
  );
181
181
  }
182
182
  if (state2) {
183
- state2.value = binding.value;
183
+ state2.value = binding.value != null ? vue.markRaw(binding.value) : binding.value;
184
184
  state2.vnode = vnode;
185
185
  }
186
186
  },
@@ -188,7 +188,7 @@ function createVue3Directive(hooks) {
188
188
  },
189
189
  unmounted(el, binding, vnode) {
190
190
  if (hooks.unmounted) {
191
- hooks.unmounted(el, normalizeBindingVue3(binding), vnode);
191
+ hooks.unmounted(el, normalizeBinding$1(binding), vnode);
192
192
  }
193
193
  const state2 = el.__directix_state__;
194
194
  if (state2 == null ? void 0 : state2.cleanup) {
@@ -197,9 +197,8 @@ function createVue3Directive(hooks) {
197
197
  delete el.__directix_state__;
198
198
  }
199
199
  };
200
- return directive;
201
200
  }
202
- function normalizeBindingVue3(binding) {
201
+ function normalizeBinding$1(binding) {
203
202
  var _a2;
204
203
  return {
205
204
  value: binding.value,
@@ -21973,6 +21972,163 @@ function teleportContent(content, options) {
21973
21972
  }
21974
21973
  };
21975
21974
  }
21975
+ function isCustomElement(el) {
21976
+ return el.tagName.includes("-") || customElements.get(el.tagName.toLowerCase()) !== void 0;
21977
+ }
21978
+ function applyDirectiveToCustomElement(el, directive, value, options) {
21979
+ const binding = {
21980
+ value,
21981
+ oldValue: null,
21982
+ arg: options == null ? void 0 : options.arg,
21983
+ modifiers: (options == null ? void 0 : options.modifiers) || {},
21984
+ instance: null
21985
+ };
21986
+ const vnode = { el };
21987
+ const mountedHook = directive.mounted;
21988
+ if (mountedHook) {
21989
+ mountedHook(el, binding, vnode, null);
21990
+ }
21991
+ return () => {
21992
+ const unmountedHook = directive.unmounted;
21993
+ if (unmountedHook) {
21994
+ unmountedHook(el, binding, vnode, null);
21995
+ }
21996
+ };
21997
+ }
21998
+ function defineCustomElementDirective(options) {
21999
+ const { name, directive, defaultValue, shadow = false, shadowMode = "open" } = options;
22000
+ class DirectiveCustomElement extends HTMLElement {
22001
+ constructor() {
22002
+ super();
22003
+ __publicField(this, "cleanup");
22004
+ __publicField(this, "currentValue", defaultValue);
22005
+ if (shadow) {
22006
+ this.attachShadow({ mode: shadowMode });
22007
+ }
22008
+ }
22009
+ connectedCallback() {
22010
+ this.cleanup = applyDirectiveToCustomElement(
22011
+ this,
22012
+ directive,
22013
+ this.currentValue
22014
+ );
22015
+ }
22016
+ disconnectedCallback() {
22017
+ if (this.cleanup) {
22018
+ this.cleanup();
22019
+ this.cleanup = void 0;
22020
+ }
22021
+ }
22022
+ // Allow setting value via attribute
22023
+ static get observedAttributes() {
22024
+ return ["value"];
22025
+ }
22026
+ attributeChangedCallback(attrName, oldValue, newValue) {
22027
+ if (attrName === "value" && oldValue !== newValue) {
22028
+ this.currentValue = newValue;
22029
+ if (this.cleanup) {
22030
+ this.cleanup();
22031
+ }
22032
+ this.cleanup = applyDirectiveToCustomElement(
22033
+ this,
22034
+ directive,
22035
+ this.currentValue
22036
+ );
22037
+ }
22038
+ }
22039
+ }
22040
+ customElements.define(name, DirectiveCustomElement);
22041
+ }
22042
+ function createDirectiveElement(_name, directive, options) {
22043
+ const { defaultValue, shadow = false, shadowMode = "open" } = options || {};
22044
+ return class extends HTMLElement {
22045
+ constructor() {
22046
+ super();
22047
+ __publicField(this, "cleanup");
22048
+ __publicField(this, "currentValue", defaultValue);
22049
+ if (shadow) {
22050
+ this.attachShadow({ mode: shadowMode });
22051
+ }
22052
+ }
22053
+ connectedCallback() {
22054
+ this.cleanup = applyDirectiveToCustomElement(
22055
+ this,
22056
+ directive,
22057
+ this.currentValue
22058
+ );
22059
+ }
22060
+ disconnectedCallback() {
22061
+ if (this.cleanup) {
22062
+ this.cleanup();
22063
+ this.cleanup = void 0;
22064
+ }
22065
+ }
22066
+ static get observedAttributes() {
22067
+ return ["value"];
22068
+ }
22069
+ attributeChangedCallback(_attrName, oldValue, newValue) {
22070
+ if (oldValue !== newValue) {
22071
+ this.currentValue = newValue;
22072
+ if (this.cleanup) {
22073
+ this.cleanup();
22074
+ }
22075
+ this.cleanup = applyDirectiveToCustomElement(
22076
+ this,
22077
+ directive,
22078
+ this.currentValue
22079
+ );
22080
+ }
22081
+ }
22082
+ };
22083
+ }
22084
+ function registerDirectiveElements(elements) {
22085
+ Object.entries(elements).forEach(([elementName, elementDirective]) => {
22086
+ const elementClass = createDirectiveElement(elementName, elementDirective);
22087
+ customElements.define(elementName, elementClass);
22088
+ });
22089
+ }
22090
+ function isCustomElementDefined(name) {
22091
+ return customElements.get(name) !== void 0;
22092
+ }
22093
+ function whenCustomElementDefined(name) {
22094
+ return __async(this, null, function* () {
22095
+ yield customElements.whenDefined(name);
22096
+ });
22097
+ }
22098
+ function getRegisteredCustomElements() {
22099
+ const registry = customElements.__registry;
22100
+ if (registry && typeof registry.keys === "function") {
22101
+ return Array.from(registry.keys());
22102
+ }
22103
+ return [];
22104
+ }
22105
+ function hydrateCustomElements(root = document.body) {
22106
+ const customElementsList = root.querySelectorAll("*");
22107
+ customElementsList.forEach((el) => {
22108
+ var _a2;
22109
+ if (isCustomElement(el)) {
22110
+ const clone = el.cloneNode(true);
22111
+ (_a2 = el.parentNode) == null ? void 0 : _a2.replaceChild(clone, el);
22112
+ }
22113
+ });
22114
+ }
22115
+ function createSSRSafeCustomElement(name, directive, options) {
22116
+ const { styles, shadow = false } = options || {};
22117
+ const ssrRender = (attrs = {}) => {
22118
+ const attrString = Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ");
22119
+ if (shadow) {
22120
+ const stylesString = styles ? `<style>${Array.isArray(styles) ? styles.join("") : styles}</style>` : "";
22121
+ return `<${name} ${attrString}><template shadowroot="open">${stylesString}<slot></slot></template></${name}>`;
22122
+ }
22123
+ return `<${name} ${attrString}></${name}>`;
22124
+ };
22125
+ const elementClass = typeof window === "undefined" ? class extends HTMLElement {
22126
+ } : createDirectiveElement(name, directive, options);
22127
+ return {
22128
+ elementClass,
22129
+ ssrRender
22130
+ };
22131
+ }
21976
22132
  const zhCN = {
21977
22133
  directives: {
21978
22134
  debounce: {
@@ -24087,6 +24243,7 @@ exports.addNonPassiveListener = addNonPassiveListener;
24087
24243
  exports.addPassiveListener = addPassiveListener;
24088
24244
  exports.announce = announce;
24089
24245
  exports.applyAriaAttributes = applyAriaAttributes;
24246
+ exports.applyDirectiveToCustomElement = applyDirectiveToCustomElement;
24090
24247
  exports.assert = assert;
24091
24248
  exports.assertPositive = assertPositive;
24092
24249
  exports.assertRange = assertRange;
@@ -24134,6 +24291,7 @@ exports.createDebouncedResizeHandler = createDebouncedResizeHandler;
24134
24291
  exports.createDelayedClick = createDelayedClick;
24135
24292
  exports.createDeprecationWarning = createDeprecationWarning;
24136
24293
  exports.createDirectiveBenchmark = createDirectiveBenchmark;
24294
+ exports.createDirectiveElement = createDirectiveElement;
24137
24295
  exports.createDirectiveTemplate = createDirectiveTemplate;
24138
24296
  exports.createEventDirective = createEventDirective;
24139
24297
  exports.createI18n = createI18n;
@@ -24144,6 +24302,7 @@ exports.createNumberFormatter = createNumberFormatter;
24144
24302
  exports.createPerformanceBudget = createPerformanceBudget;
24145
24303
  exports.createPermissionCheck = createPermissionCheck;
24146
24304
  exports.createPermissionChecker = createPermissionChecker;
24305
+ exports.createSSRSafeCustomElement = createSSRSafeCustomElement;
24147
24306
  exports.createSafeContentHandler = createSafeContentHandler;
24148
24307
  exports.createSafeDirectiveWrapper = createSafeDirectiveWrapper;
24149
24308
  exports.createStyleDirective = createStyleDirective;
@@ -24158,6 +24317,7 @@ exports.deepClone = deepClone;
24158
24317
  exports.deepMerge = deepMerge;
24159
24318
  exports.deferNonCriticalDirective = deferNonCriticalDirective;
24160
24319
  exports.deferTask = deferTask;
24320
+ exports.defineCustomElementDirective = defineCustomElementDirective;
24161
24321
  exports.defineDirective = defineDirective;
24162
24322
  exports.defineDirectiveGroup = defineDirectiveGroup;
24163
24323
  exports.definePlugin = definePlugin;
@@ -24263,6 +24423,7 @@ exports.getPermissionManager = getPermissionManager;
24263
24423
  exports.getPluginManager = getPluginManager;
24264
24424
  exports.getPluginRegistry = getPluginRegistry;
24265
24425
  exports.getPolyfillStatus = getPolyfillStatus;
24426
+ exports.getRegisteredCustomElements = getRegisteredCustomElements;
24266
24427
  exports.getSlowestDirectives = getSlowestDirectives;
24267
24428
  exports.getSupportedRegions = getSupportedRegions;
24268
24429
  exports.getTimezoneInfo = getTimezoneInfo;
@@ -24273,6 +24434,7 @@ exports.handleSSRUnsupported = handleSSRUnsupported;
24273
24434
  exports.handleTouchConflict = handleTouchConflict;
24274
24435
  exports.hasPermission = hasPermission$2;
24275
24436
  exports.hasPermissionSync = hasPermissionSync;
24437
+ exports.hydrateCustomElements = hydrateCustomElements;
24276
24438
  exports.importConfig = importConfig;
24277
24439
  exports.incrementCounter = incrementCounter;
24278
24440
  exports.info = info;
@@ -24286,6 +24448,8 @@ exports.isArray = isArray;
24286
24448
  exports.isBoolean = isBoolean;
24287
24449
  exports.isBrowser = isBrowser;
24288
24450
  exports.isBrowserSupported = isBrowserSupported;
24451
+ exports.isCustomElement = isCustomElement;
24452
+ exports.isCustomElementDefined = isCustomElementDefined;
24289
24453
  exports.isDOMReady = isDOMReady;
24290
24454
  exports.isDevtoolsAvailable = isDevtoolsAvailable;
24291
24455
  exports.isEmpty = isEmpty;
@@ -24335,6 +24499,7 @@ exports.prefetchVisibleElements = prefetchVisibleElements;
24335
24499
  exports.preloadModule = preloadModule;
24336
24500
  exports.quickPrint = quickPrint;
24337
24501
  exports.recordHistogram = recordHistogram;
24502
+ exports.registerDirectiveElements = registerDirectiveElements;
24338
24503
  exports.registerPolyfill = registerPolyfill;
24339
24504
  exports.removeHealthCheck = removeHealthCheck;
24340
24505
  exports.requestIdleCallback = requestIdleCallback;
@@ -24522,6 +24687,7 @@ exports.warnUnsupportedFeatureOnce = warnUnsupportedFeatureOnce;
24522
24687
  exports.warnUnsupportedFeatures = warnUnsupportedFeatures;
24523
24688
  exports.watchConfig = watchConfig;
24524
24689
  exports.watchEffectBinding = watchEffectBinding;
24690
+ exports.whenCustomElementDefined = whenCustomElementDefined;
24525
24691
  exports.withAuditLog = withAuditLog;
24526
24692
  exports.withErrorRecovery = withErrorRecovery;
24527
24693
  exports.withPerformanceMonitoring = withPerformanceMonitoring;