@gitlab/ui
Version:
GitLab UI Components
112 lines (103 loc) • 3.48 kB
JavaScript
import { isVue3 } from '../vue';
// Regex to detect event handler props: onSomething or onSomethingOnce
const EVENT_HANDLER_RE = /^on([A-Z][a-zA-Z]*)$/;
const ONCE_SUFFIX = 'Once';
/**
* Converts an event name to a handler prop name.
* Use as computed property key with event constants: [eventProp(EVENT_NAME_HIDDEN)]
* @param {string} eventName - The event name (e.g., 'hidden', 'show', 'mouseenter')
* @param {Object} options - Options object
* @param {boolean} options.once - If true, returns the "once" variant (e.g., 'onHiddenOnce')
* @returns {string} The handler prop name (e.g., 'onHidden', 'onHiddenOnce')
*/
const eventProp = function (eventName) {
let {
once = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const capitalized = eventName.charAt(0).toUpperCase() + eventName.slice(1);
return `on${capitalized}${once ? ONCE_SUFFIX : ''}`;
};
/**
* Parses a handler prop name to extract event name and once flag.
* Examples:
* onShow -> { eventName: 'show', once: false }
* onShowOnce -> { eventName: 'show', once: true }
* onMouseenter -> { eventName: 'mouseenter', once: false }
*/
const parseEventHandlerProp = propName => {
const match = propName.match(EVENT_HANDLER_RE);
if (!match) return null;
let eventPart = match[1];
const once = eventPart.endsWith(ONCE_SUFFIX);
if (once) eventPart = eventPart.slice(0, -ONCE_SUFFIX.length);
const eventName = eventPart.charAt(0).toLowerCase() + eventPart.slice(1);
return {
eventName,
once
};
};
/**
* Extracts event handlers from config and separates them from other props.
* @param {Object} config - The config object with potential event handler props
* @returns {{ handlers: Array<{eventName: string, handler: Function, once: boolean}>, cleanConfig: Object }}
*/
const extractEventHandlers = config => {
const handlers = [];
const cleanConfig = {
...config
};
if (cleanConfig.propsData) {
const cleanPropsData = {};
Object.keys(cleanConfig.propsData).forEach(propName => {
const parsed = parseEventHandlerProp(propName);
if (parsed && typeof cleanConfig.propsData[propName] === 'function') {
handlers.push({
...parsed,
handler: cleanConfig.propsData[propName]
});
} else {
cleanPropsData[propName] = cleanConfig.propsData[propName];
}
});
cleanConfig.propsData = cleanPropsData;
}
return {
handlers,
cleanConfig
};
};
const createNewChildComponent = function (parent, Component) {
let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
const bvEventRoot = parent.$root ? parent.$root.$options.bvEventRoot || parent.$root : null;
// Vue 3: pass handlers as props directly (Vue 3 converts onXxx props to listeners)
if (isVue3(parent)) {
return new Component({
...config,
parent,
bvParent: parent,
bvEventRoot
});
}
// Vue 2: extract handlers and subscribe manually after creation
const {
handlers,
cleanConfig
} = extractEventHandlers(config);
const instance = new Component({
...cleanConfig,
parent,
bvParent: parent,
bvEventRoot
});
// Subscribe to events using $on/$once
handlers.forEach(_ref => {
let {
eventName,
handler,
once
} = _ref;
instance[once ? '$once' : '$on'](eventName, handler);
});
return instance;
};
export { createNewChildComponent, eventProp };