UNPKG

@brusalk/react-wow-addon

Version:

React-style UI Framework for World of Warcraft AddOns

208 lines (207 loc) 7.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pascalCase = exports.sentenceCase = exports.P = exports.updateFrameProperties = exports.cleanupFrame = exports.createFrame = void 0; const frameCache = {}; function getCache(type) { // if (frameCache[type]) { // return frameCache[type].length ? frameCache[type].pop() : undefined; // } return undefined; } function setCache(frame) { const type = frame.GetObjectType(); print('store cache', type); if (frameCache[type] && frameCache[type].length) { frameCache[type].push(frame); } else { frameCache[type] = [frame]; } } function createFrame(jsxType, parentFrame, props) { const frameType = pascalCase(jsxType); let frame = getCache(frameType); if (frame) { print('got frame from cache', frameType, frame, 'parent:', parentFrame); frame.SetParent(parentFrame); frame.Show(); return frame; } if (frameType === 'FontString') { frame = parentFrame .CreateFontString(props.name, props.DrawLayer || 'ARTWORK', props.inheritsFrom); } else if (frameType === 'Texture') { frame = parentFrame .CreateTexture(props.name, props.DrawLayer || 'ARTWORK', props.inheritsFrom); } else { frame = CreateFrame(frameType, props.name, parentFrame, props.inheritsFrom || "BackdropTemplate"); } // frame.SetParent(parentFrame); print('created frame:', frameType); return frame; } exports.createFrame = createFrame; function cleanupFrame(frame) { print('cleaning up frame', frame.GetObjectType(), frame); frame.Hide(); frame.ClearAllPoints(); if (frame.GetObjectType() === 'Texture' || frame.GetObjectType() === 'FontString') { frame.SetParent(UIParent); } else { frame.SetParent(null); } setCache(frame); } exports.cleanupFrame = cleanupFrame; const isEvent = (name) => name.startsWith('On'); const isStandardProperty = (name) => !isEvent(name) && !isOrderedProperty(name) && name !== 'children' && name !== 'Points' && name !== 'Point' && name !== 'name' && name !== 'DrawLayer' && name !== 'inheritsFrom' && name !== 'Clickable' && name !== 'Draggable'; /** * These properties must be set _before_ their other properties e.g. Background * must be set before BackgroundColor */ const isOrderedProperty = (name) => name === 'Font' || name === 'Background' || name === 'Texture' || name === 'Backdrop'; /** * These properties take table values, which should be set verbatim. Array * values will apply each item as an argument to SetX. These values should not * be interpreted as arrays. */ const isTableValue = (name) => name === 'Backdrop'; function updateFrameProperties(frame, prevProps, nextProps) { updateFramePoints(frame, nextProps); updateFrameLayer(frame, nextProps); updateFrameEvents(frame, prevProps, nextProps); updateOrderSpecificProperties(frame, prevProps, nextProps); updateRemainingProperties(frame, prevProps, nextProps); } exports.updateFrameProperties = updateFrameProperties; function updateOrderSpecificProperties(frame, prevProps, nextProps) { // Remove properties that are no longer specified Object.keys(prevProps) .filter(key => isOrderedProperty(key) && !nextProps[key]) .forEach(key => { attemptSetProperty(frame, key, null); }); // Set properties Object.keys(nextProps).filter(isOrderedProperty).forEach(key => { attemptSetProperty(frame, key, nextProps[key]); }); } function updateRemainingProperties(frame, prevProps, nextProps) { // Remove properties that are no longer specified Object.keys(prevProps) .filter(key => isStandardProperty(key) && !nextProps[key]) .forEach(key => { attemptSetProperty(frame, key, null); }); // Set properties Object.keys(nextProps).filter(isStandardProperty).forEach(key => { attemptSetProperty(frame, key, nextProps[key]); }); } function updateFrameEvents(frame, prevProps, nextProps) { // Detach removed event listeners Object.keys(prevProps) .filter(key => isEvent(key) && !nextProps[key]) .forEach(event => { frame.SetScript(event, undefined); }); if (nextProps['Clickable']) { frame.RegisterForClicks('RightButton'); } if (nextProps['Draggable']) { frame.RegisterForDrag(...nextProps['Draggable']); } // Add new event listeners Object.keys(nextProps) .filter(key => isEvent(key) && prevProps[key] !== nextProps[key]) .forEach(event => { // print('attaching event', event); frame.SetScript(event, nextProps[event]); }); } /** Handle frame points, size to parent unless specified. */ function updateFramePoints(frame, nextProps) { frame.ClearAllPoints(); if (nextProps.Point) { setPoint(frame, nextProps.Point); return; } if (nextProps.Points) { const points = nextProps.Points; points.forEach(pointDef => setPoint(frame, pointDef)); } else { // Fill to parent frame.SetAllPoints(); } } /** Handle frame points, size to parent unless specified. */ function updateFrameLayer(frame, nextProps) { const region = frame; const layer = nextProps.DrawLayer; if (!layer || typeof region.SetDrawLayer !== 'function') { return; } if (typeof layer === 'string') { region.SetDrawLayer(layer, 0); return; } region.SetDrawLayer(layer[0], layer[1]); } /** Create a point declaration */ function P(point, x, y, relativePoint, relativeFrame) { // TODO: memoize for perf return { point, relativePoint, relativeFrame, x, y }; } exports.P = P; function setPoint(frame, pointDef) { if (typeof pointDef === 'string') { frame.SetPoint(pointDef); } else { const { point, relativePoint, relativeFrame, x, y } = pointDef; const relativeTo = relativePoint || point; // print('setPoint', Object.keys(pointDef).join(', ')); if (relativeFrame) { frame.SetPoint(point, relativeFrame, relativeTo, x || 0, y || 0); } else { const parent = frame.GetParent(); frame.SetPoint(point, parent, relativeTo, x || 0, y || 0); } } } function attemptSetProperty(frame, key, value) { const region = frame; const setter = `Set${key}`; const setterFn = region[setter]; assert(setterFn, `Tried to use ${setter} and it did not exist on ${region}`); if (setterFn && typeof setterFn == 'function') { if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || isTableValue(key)) { region[setter](value); } else { // print( `calling ${setter} with array elements as args:`, // (value as any[]).join(', ')); setterFn.apply(region, value); } } } function sentenceCase(str) { return str[0].toUpperCase() + str.slice(1).toLowerCase(); } exports.sentenceCase = sentenceCase; function pascalCase(kebabCase) { return kebabCase.split('-').map(sentenceCase).join(''); } exports.pascalCase = pascalCase;