import { useState, useMemo } from 'react' /** @type {String} class to apply to buttons on open menu items */ const iconButtonClass = 'btn btn-xs btn-ghost px-0 text-accent' /** * A generic component for handling a menu item. * Wraps the given input in a {@see Collapse} with the appropriate buttons * @param {String} options.name the name of the item, for using as a key * @param {Object} options.config the configuration for the input * @param {Sting|Boolean|Number} options.current the current value of the item * @param {Function} options.updateFunc the function that will be called by event handlers to update the value * @param {Function} options.t the translation function * @param {Object} options.passProps props to pass to the Input component * @param {Boolean} changed has the value changed from default? * @param {React.Component} Input the input component this menu item will use * @param {React.Component} Value a value display component this menu item will use * @param {Boolean} allowOverride all a text input to be used to override the given input component * @param {Number} ux the user-defined ux level * @param {object} props.Swizzled - An object holding swizzled code */ export const MenuItem = ({ name, Swizzled, current, updateHandler, passProps = {}, changed, Input = () => {}, allowOverride = false, ux = 5, docs, config, Design, }) => { // Local state - whether the override input should be shown const [override, setOverride] = useState(false) // generate properties to pass to the Input const drillProps = useMemo( () => ({ name, config, ux, current, updateHandler, t: Swizzled.methods.t, changed, override, Design, ...passProps, }), [name, config, current, updateHandler, changed, override, passProps, ux] ) if (!config) { console.log('no config in containers', { name, current, config }) return null } // don't render if this item is more advanced than the user has chosen to see if (config.ux && config.ux > ux) return null // get buttons for open and closed states const buttons = [] if (allowOverride) buttons.push( ) const ResetButton = ({ disabled = false }) => ( ) buttons.push() return ( {Swizzled.methods.t(`${name}.d`)}} id={config.name} labelBR={
{buttons}
} labelBL={ {Swizzled.methods.t(`pe:youAreUsing${changed ? 'ACustom' : 'TheDefault'}Value`)} } docs={docs} >
) } /** * A component for recursively displaying groups of menu items. * Accepts any object where menu item configurations are keyed by name * Items that are group headings are expected to have an isGroup: true property * @param {Boolean} options.collapsible Should this group be collapsible (use false for the top level of a menu) * @param {Number} options.ux the user-defined ux level * @param {String} options.name the name of the group or item * @param {Object} options.currentValues a map of current values for items in the group, keyed by name * @param {Object} structure the configuration for the group. * @param {React.Component} Icon the icon to display next to closed groups * @param {React.Component} Item the component to use for menu items * @param {Object} values a map of Value display components to be used by menu items in the group * @param {Object} inputs a map of Input components to be used by menu items in the group * @param {Object} passProps properties to pass to Inputs within menu items * @param {Object} emojis a map of emojis to use as icons for groups or items * @param {Function} updateHandler the function called by change handlers on inputs within menu items * @param {Boolean} topLevel is this group the top level group? false for nested * @param {Function} t translation function * @param {object} props.Swizzled - An object holding swizzled code */ export const MenuItemGroup = ({ collapsible = true, ux, currentValues = {}, structure, Icon, Item = false, inputs = {}, values = {}, passProps = {}, updateHandler, topLevel = false, isDesignOptionsGroup = false, Design, Swizzled, state, }) => { if (!Item) Item = Swizzled.components.MenuItem // map the entries in the structure const content = Object.entries(structure).map(([itemName, item]) => { // if it's the isGroup property, or it is false, it shouldn't be shown if (itemName === 'isGroup' || item === false) return null if (!item) return null if (item.ux && ux && item.ux > ux) return null const ItemIcon = item.icon ? item.icon : item.isGroup ? Swizzled.components.GroupIcon : Icon ? Icon : () => fixme-icon const Value = item.isGroup ? () => (
{Object.keys(item).filter((i) => i !== 'isGroup').length}
) : isDesignOptionsGroup ? values[Swizzled.methods.designOptionType(item)] : values[itemName] ? values[itemName] : () => ¯\_(ツ)_/¯ return [
{Swizzled.methods.t([`pe:${itemName}.t`, `pe:${itemName}`])}
, item.isGroup ? ( ) : ( ), itemName, ] }) return item !== null)} /> } /** * A generic component to present the title of a menu item * @param {String} options.name the name of the item, to act as its translation key * @param {Function} options.t the translation function * @param {String|React.Component} options.current a the current value, or a Value component to display it * @param {Boolean} options.open is the menu item open? * @param {String} options.emoji the emoji icon of the menu item */ export const MenuItemTitle = ({ name, current = null, open = false, emoji = '', Icon = false, Swizzled, }) => (
{Icon ? : {emoji}} {Swizzled.methods.t([`${name}.t`, name])} {current}
)