-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Props hoc #3084
base: dev
Are you sure you want to change the base?
Props hoc #3084
Conversation
WalkthroughThis pull request introduces design configuration enhancements across components. The button demo now wraps Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CP as ConfigProvider
participant TR as TinyRow
participant TB as TinyButton
User->>CP: Initiate button interaction
CP->>TR: Wraps TinyButton(s)
TR->>TB: Supplies design settings (resetTime=0, size='mini')
TB->>User: Renders configured button
sequenceDiagram
participant BC as BaseComponent
participant HOC as WithDesignConfigPropsDefineComponent
participant GC as GlobalDesignConfig
participant Render as EnhancedComponent
BC->>HOC: Wrapped by HOC
HOC->>GC: Inject global design config
GC-->>HOC: Returns design properties
HOC->>Render: Merge props and render component
Render->>User: Display enhanced component
Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 ESLint
packages/vue-common/src/adapter/vue2.7/hoc.tsxOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-vue". (The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. packages/vue-common/src/adapter/vue2.7/index.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-vue". (The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. examples/sites/demos/pc/app/button/basic-usage.vueOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-vue". (The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
WalkthroughThis PR introduces a new feature by adding the Changes
|
methods: { | ||
// 解包可能存在的响应式对象 | ||
unwrap(config) { | ||
if (config && typeof config === 'object' && 'value' in config) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that the unwrap
method correctly handles all possible types of reactive objects to avoid unexpected behavior.
[e2e-test-warn] The title of the Pull request should look like "fix(vue-renderless): [action-menu, alert] fix xxx bug". Please make sure you've read our contributing guide |
methods: { | ||
// 解包可能存在的响应式对象 | ||
unwrap(config) { | ||
if (config && typeof config === 'object' && 'value' in config) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that the unwrap
method correctly handles all possible types of reactive objects to avoid unexpected behavior.
// 获取组件级配置和全局配置(inject需要带有默认值,否则控制台会报警告) | ||
let globalDesignConfig = hooks.inject(design.configKey, {}) | ||
// globalDesignConfig 可能是响应式对象,比如 computed | ||
globalDesignConfig = globalDesignConfig?.value || globalDesignConfig || {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that the globalDesignConfig
is correctly unwrapped to handle all possible types of reactive objects to avoid unexpected behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/vue-common/src/adapter/vue2/hoc.tsx (3)
14-28
: Consider adding error handling for method exposureThe method exposure implementation watches for changes to
innerRef
and copies methods to the wrapper instance. While functional, this approach could be more robust.Consider adding error handling to prevent potential issues when accessing methods:
created() { // 暴露实例方法 this.$watch( () => this.innerRef, (val) => { if (val) { Object.keys(val).forEach((key) => { if (!(key in this)) { + try { this[key] = val[key] + } catch (err) { + console.warn(`[DesignConfigHOC] Failed to expose method ${key}:`, err) + } } }) } } ) }
34-48
: Consider adding component name to HOC for better debuggingThe HOC name is currently hardcoded as 'DesignConfigHOC', which may make debugging difficult when multiple components are wrapped.
Consider including the base component name in the HOC name:
export default function DesignConfigPropsHOC(BaseComponent) { + const componentName = BaseComponent.name || (BaseComponent.options && BaseComponent.options.name) || 'Unknown' return Vue.extend({ - name: 'DesignConfigHOC', + name: `DesignConfigHOC(${componentName})`, functional: false, // rest of the implementation...
50-57
: Enhance unwrap method to handle more reactive typesThe current implementation may not handle all types of reactive objects in Vue ecosystem.
Consider expanding the unwrap method to handle more types of reactive objects:
unwrap(config) { if (config && typeof config === 'object') { // Handle Vue 2 reactivity if ('value' in config && typeof config.value !== 'undefined') { return config.value } + // Handle ref-like objects + if (typeof config.getValue === 'function') { + return config.getValue() + } } return config || {} }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
examples/sites/demos/pc/app/button/basic-usage.vue
(3 hunks)examples/vue3/package.json
(3 hunks)packages/vue-common/src/adapter/vue2.7/hoc.tsx
(1 hunks)packages/vue-common/src/adapter/vue2.7/index.ts
(2 hunks)packages/vue-common/src/adapter/vue2/hoc.tsx
(1 hunks)packages/vue-common/src/adapter/vue2/index.ts
(2 hunks)packages/vue-common/src/adapter/vue3/hoc.tsx
(1 hunks)packages/vue-common/src/adapter/vue3/index.ts
(2 hunks)packages/vue-common/src/index.ts
(2 hunks)packages/vue/src/button/src/index.ts
(1 hunks)
🔇 Additional comments (27)
packages/vue/src/button/src/index.ts (1)
12-12
: Import updated to use WithDesignConfigPropsDefineComponentThe import statement has been modified to use the new
WithDesignConfigPropsDefineComponent
(aliased asdefineComponent
) instead of the directdefineComponent
from@opentiny/vue-common
. This change enables the Button component to support global design configurations.packages/vue-common/src/adapter/vue3/index.ts (2)
16-16
: Added DesignConfigPropsHOC importThis import is required for the new
WithDesignConfigPropsDefineComponent
function.
481-488
: Added WithDesignConfigPropsDefineComponent functionThis new function implements a Higher-Order Component pattern to enhance components with design configuration capabilities. The implementation correctly wraps the component definition with the
DesignConfigPropsHOC
after processing it with Vue'sdefineComponent
.The commented example code also provides good guidance on usage.
examples/sites/demos/pc/app/button/basic-usage.vue (4)
5-12
: Added ConfigProvider to demonstrate design prop configurationThe basic buttons section has been wrapped with the new
ConfigProvider
component, demonstrating how to provide design configuration to button components. This serves as an excellent usage example for the new feature.
45-45
: Added ConfigProvider to importsThe ConfigProvider component has been properly imported from the @opentiny/vue package.
52-54
: Registered ConfigProvider in components objectConfigProvider has been correctly added to the components registration.
63-72
: Added design configuration to component dataThis data property defines the design configuration that will be provided to all Button components within the ConfigProvider. The structure is well-organized with proper nesting for component-specific props.
examples/vue3/package.json (2)
15-15
: Updated unit test command to use the UI interfaceThe unit test command now includes the
--ui
flag to enable the Vitest UI interface, which provides a better testing experience.
40-40
: Updated @vitest/ui dependency to a newer versionThe @vitest/ui package has been upgraded from ^0.31.0 to ^2.1.9, which is a significant version bump that provides newer features and bug fixes for the test UI interface.
packages/vue-common/src/adapter/vue2/index.ts (2)
6-6
: Import addition looks goodThis correctly imports the
DesignConfigPropsHOC
from the local HOC implementation file.
346-353
: Well-structured HOC implementation with good documentationThe implementation of
WithDesignConfigPropsDefineComponent
follows the correct pattern for a higher-order component that wraps Vue's defineComponent. The commented example provides clear guidance on how to use this new function.A few observations:
- The function correctly takes a BaseComponent as input
- It properly composes the HOC with defineComponent
- TypeScript typing is correctly applied
- The example demonstrates the intended use case
This implementation will allow components to receive design configuration properties while maintaining compatibility with Vue's component definition API.
packages/vue-common/src/adapter/vue2.7/index.ts (2)
16-16
: Import addition looks goodThis correctly imports the
DesignConfigPropsHOC
from the Vue 2.7-specific HOC implementation.
345-352
: Consistent implementation across Vue versionsThe implementation of
WithDesignConfigPropsDefineComponent
for Vue 2.7 matches the Vue 2 implementation, ensuring consistent behavior across Vue versions. The comment example is also helpful for developers.packages/vue-common/src/adapter/vue3/hoc.tsx (4)
1-4
: Appropriate imports for Vue 3 HOCThe imports are well structured:
- Using Vue 3's type system with
SetupContext
- Importing design utilities and hooks from the common index
- Importing the helper function
getComponentName
from the adapterThis sets up the necessary dependencies for the HOC implementation.
5-20
: Well-designed global configuration injectionThe HOC implementation correctly:
- Preserves the original component's properties
- Sets up a ref for exposing the inner component
- Injects the global design configuration with a default empty object
- Handles potentially reactive configuration objects
- Retrieves component-specific configuration
- Merges configuration props with passed attrs
This approach ensures design configurations are properly injected while maintaining component functionality.
20-33
: Effective method exposure through proxy patternThe implementation uses a Proxy to expose the inner component's methods, which is a clean approach to forward method calls and property access to the wrapped component. This maintains the component's public API.
34-43
: Clean rendering implementation for Vue 3The render function correctly:
- Returns a JSX implementation of the BaseComponent
- Spreads the merged props to the component
- Passes the inner ref for method exposure
- Passes through slots
This completes the HOC pattern appropriately for Vue 3's composition API.
packages/vue-common/src/adapter/vue2.7/hoc.tsx (6)
1-3
: Appropriate imports for Vue 2.7 HOCThe imports include Vue and the required design utilities while keeping the dependencies minimal.
4-14
: Effective dependency injection setupThe HOC implementation correctly:
- Uses Vue.extend for Vue 2.7 compatibility
- Sets up dependency injection for the design configuration
- Provides a default empty object to prevent errors
This approach ensures consistent behavior with Vue 2.7's component model.
14-33
: Clean method exposure patternThe created hook and watcher setup provide an elegant solution for exposing the inner component's methods to the outer component instance. The data initialization for innerRef is appropriately defined.
34-48
: Well-designed computed propertiesThe computed properties correctly:
- Extract the component name by removing the prefix
- Handle the unwrapping of potentially reactive configuration objects
- Merge component-specific props with passed attributes
This ensures the design configuration is properly applied to the component.
49-57
: Robust configuration handlingThe unwrap method properly handles different types of configuration objects, including reactive objects with a .value property. This ensures compatibility with both direct objects and computed properties.
58-73
: Appropriate render implementation for Vue 2.7The render function correctly:
- Creates the BaseComponent with h function
- Sets up the ref callback to store the component instance
- Passes merged props as attrs
- Forwards listeners and slots
This completes the HOC pattern appropriately for Vue 2.7's rendering model.
packages/vue-common/src/index.ts (2)
24-24
: LGTM: Import line updated to include WithDesignConfigPropsDefineComponentThe import now includes the new Higher-Order Component for design configuration, which aligns with the PR objective.
40-40
: LGTM: Export updated to include WithDesignConfigPropsDefineComponentThe export correctly makes the new HOC available to other components in the application.
packages/vue-common/src/adapter/vue2/hoc.tsx (2)
4-73
: Implementation of DesignConfigPropsHOC looks goodThis HOC effectively wraps components with design configuration capabilities, allowing for global design props to be merged with component-specific attributes.
The implementation:
- Correctly injects the global design configuration
- Computes component name by removing the prefix
- Merges component-specific design props with passed attributes
- Handles exposing inner component methods to the wrapper component
- Properly renders the base component with all necessary props and slots
58-71
: LGTM: Render function implementationThe render function correctly passes all necessary props, listeners, and slots to the base component while setting up the reference for method exposure.
@@ -9,7 +9,7 @@ | |||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. | |||
* | |||
*/ | |||
import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common' | |||
import { $props, $prefix, $setup, WithDesignConfigPropsDefineComponent as defineComponent } from '@opentiny/vue-common' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果这样修改可能会对现有业务造成影响,你这操作相当于包了一层组件转发下props,能不能通过某一个全局配置可以让用户自己选择是否开启这个功能,不要对存量业务造成影响
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
为 vue3及 vue2 增加 WithDesignConfigPropsDefineComponent 方法
组件中引入 defineComponent 的地方改为 WithDesignConfigPropsDefineComponent
import { $props, $prefix, $setup, WithDesignConfigPropsDefineComponent as defineComponent } from '@opentiny/vue-common'
目前仅 Button 进行了调整,Vue2,Vue3中都达到了预期的效果,Button 组件Vue3版本单元测试也能正常通过
Issue Number: #2940
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
Tests