add toggler to boolean menu items
This commit is contained in:
parent
f37274ee70
commit
2ad0ac3491
10 changed files with 197 additions and 231 deletions
|
@ -23,7 +23,7 @@ const defaultUi = {
|
||||||
|
|
||||||
const draftViews = ['draft', 'test']
|
const draftViews = ['draft', 'test']
|
||||||
|
|
||||||
export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) => {
|
export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from, set }) => {
|
||||||
// Hooks
|
// Hooks
|
||||||
const { t, i18n } = useTranslation(ns)
|
const { t, i18n } = useTranslation(ns)
|
||||||
const { language } = i18n
|
const { language } = i18n
|
||||||
|
@ -38,8 +38,9 @@ export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) =
|
||||||
// Effect
|
// Effect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Force re-render when baseSettings changes. Required when they are loaded async.
|
// Force re-render when baseSettings changes. Required when they are loaded async.
|
||||||
setSettings({ ...baseSettings, embed: true })
|
console.log('in effect')
|
||||||
}, [baseSettings])
|
setSettings({ ...baseSettings, embed: true, measurements: set.measies })
|
||||||
|
}, [baseSettings, set])
|
||||||
|
|
||||||
// Helper methods for settings/ui updates
|
// Helper methods for settings/ui updates
|
||||||
const update = {
|
const update = {
|
||||||
|
|
|
@ -2,62 +2,45 @@
|
||||||
import { loadSettingsConfig, defaultSamm } from './config.mjs'
|
import { loadSettingsConfig, defaultSamm } from './config.mjs'
|
||||||
// Components
|
// Components
|
||||||
import { SettingsIcon } from 'shared/components/icons.mjs'
|
import { SettingsIcon } from 'shared/components/icons.mjs'
|
||||||
import {
|
|
||||||
CompleteSettingInput,
|
|
||||||
LocaleSettingInput,
|
|
||||||
MarginSettingInput,
|
|
||||||
OnlySettingInput,
|
|
||||||
PaperlessSettingInput,
|
|
||||||
RendererSettingInput,
|
|
||||||
SaBoolSettingInput,
|
|
||||||
SaMmSettingInput,
|
|
||||||
ScaleSettingInput,
|
|
||||||
UnitsSettingInput,
|
|
||||||
} from './inputs.mjs'
|
|
||||||
import {
|
|
||||||
CompleteSettingValue,
|
|
||||||
LocaleSettingValue,
|
|
||||||
MarginSettingValue,
|
|
||||||
OnlySettingValue,
|
|
||||||
PaperlessSettingValue,
|
|
||||||
RendererSettingValue,
|
|
||||||
SaBoolSettingValue,
|
|
||||||
SaMmSettingValue,
|
|
||||||
ScaleSettingValue,
|
|
||||||
UnitsSettingValue,
|
|
||||||
} from './values.mjs'
|
|
||||||
import { WorkbenchMenu } from '../shared/index.mjs'
|
import { WorkbenchMenu } from '../shared/index.mjs'
|
||||||
|
import { MenuItem } from '../shared/menu-item.mjs'
|
||||||
// Facilitate lookup of the value component
|
// input components and event handlers
|
||||||
const values = {
|
import { inputs, handlers } from './inputs.mjs'
|
||||||
complete: CompleteSettingValue,
|
// values
|
||||||
locale: LocaleSettingValue,
|
import { values } from './values.mjs'
|
||||||
margin: MarginSettingValue,
|
|
||||||
only: OnlySettingValue,
|
|
||||||
paperless: PaperlessSettingValue,
|
|
||||||
renderer: RendererSettingValue,
|
|
||||||
sabool: SaBoolSettingValue,
|
|
||||||
samm: SaMmSettingValue,
|
|
||||||
scale: ScaleSettingValue,
|
|
||||||
units: UnitsSettingValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Facilitate lookup of the input component
|
|
||||||
const inputs = {
|
|
||||||
complete: CompleteSettingInput,
|
|
||||||
locale: LocaleSettingInput,
|
|
||||||
margin: MarginSettingInput,
|
|
||||||
only: OnlySettingInput,
|
|
||||||
paperless: PaperlessSettingInput,
|
|
||||||
renderer: RendererSettingInput,
|
|
||||||
sabool: SaBoolSettingInput,
|
|
||||||
samm: SaMmSettingInput,
|
|
||||||
scale: ScaleSettingInput,
|
|
||||||
units: UnitsSettingInput,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ns = ['core-settings', 'modal']
|
export const ns = ['core-settings', 'modal']
|
||||||
|
|
||||||
|
/** A wrapper for {@see MenuItem} to handle core settings-specific business */
|
||||||
|
const CoreSetting = ({ name, config, control, updateFunc, current, passProps, ...rest }) => {
|
||||||
|
// is toggling allowed?
|
||||||
|
const allowToggle = control > 3 && config.list?.length === 2
|
||||||
|
|
||||||
|
const handlerArgs = {
|
||||||
|
updateFunc,
|
||||||
|
current,
|
||||||
|
config,
|
||||||
|
...passProps,
|
||||||
|
}
|
||||||
|
// get the appropriate event handler if there is one
|
||||||
|
const handler = handlers[name] ? handlers[name](handlerArgs) : updateFunc
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
{...{
|
||||||
|
name,
|
||||||
|
config,
|
||||||
|
control,
|
||||||
|
current,
|
||||||
|
passProps,
|
||||||
|
...rest,
|
||||||
|
allowToggle,
|
||||||
|
updateFunc: handler,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The core settings menu
|
* The core settings menu
|
||||||
* @param {Object} options.update settings and ui update functions
|
* @param {Object} options.update settings and ui update functions
|
||||||
|
@ -82,6 +65,11 @@ export const CoreSettings = ({
|
||||||
parts: patternConfig.draftOrder,
|
parts: patternConfig.draftOrder,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const passProps = {
|
||||||
|
samm: typeof settings.samm === 'undefined' ? defaultSamm(settings.units) : settings.samm,
|
||||||
|
units: settings.units,
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkbenchMenu
|
<WorkbenchMenu
|
||||||
{...{
|
{...{
|
||||||
|
@ -95,12 +83,10 @@ export const CoreSettings = ({
|
||||||
language,
|
language,
|
||||||
name: 'coreSettings',
|
name: 'coreSettings',
|
||||||
ns,
|
ns,
|
||||||
passProps: {
|
passProps,
|
||||||
samm: typeof settings.samm === 'undefined' ? defaultSamm(settings.units) : settings.samm,
|
|
||||||
units: settings.units,
|
|
||||||
},
|
|
||||||
updateFunc: update.settings,
|
updateFunc: update.settings,
|
||||||
values,
|
values,
|
||||||
|
Item: CoreSetting,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,26 +1,33 @@
|
||||||
import { useCallback } from 'react'
|
|
||||||
import { measurementAsMm } from 'shared/utils.mjs'
|
import { measurementAsMm } from 'shared/utils.mjs'
|
||||||
import { ListInput, SliderInput, BoolInput, MmInput } from '../shared/inputs.mjs'
|
import { ListInput, SliderInput, BoolInput, MmInput } from '../shared/inputs.mjs'
|
||||||
|
|
||||||
export const LocaleSettingInput = ListInput
|
|
||||||
export const UnitsSettingInput = ListInput
|
|
||||||
export const RendererSettingInput = ListInput
|
|
||||||
export const CompleteSettingInput = ListInput
|
|
||||||
export const PaperlessSettingInput = ListInput
|
|
||||||
|
|
||||||
export const MarginSettingInput = MmInput
|
|
||||||
export const ScaleSettingInput = SliderInput
|
|
||||||
|
|
||||||
/** an input for the 'only' setting. toggles individual parts*/
|
/** an input for the 'only' setting. toggles individual parts*/
|
||||||
export const OnlySettingInput = (props) => {
|
const OnlySettingInput = (props) => {
|
||||||
const { config, updateFunc, current } = props
|
const { config } = props
|
||||||
|
|
||||||
// set up choice titles
|
// set up choice titles
|
||||||
config.choiceTitles = {}
|
config.choiceTitles = {}
|
||||||
config.list.forEach((p) => (config.choiceTitles[p] = p))
|
config.list.forEach((p) => (config.choiceTitles[p] = p))
|
||||||
|
|
||||||
// make an update function that toggles the parts
|
return <ListInput {...props} />
|
||||||
const onlyUpdateFunc = useCallback(
|
}
|
||||||
|
|
||||||
|
export const inputs = {
|
||||||
|
complete: ListInput,
|
||||||
|
locale: ListInput,
|
||||||
|
margin: MmInput,
|
||||||
|
only: OnlySettingInput,
|
||||||
|
paperless: BoolInput,
|
||||||
|
sabool: BoolInput,
|
||||||
|
samm: MmInput,
|
||||||
|
scale: SliderInput,
|
||||||
|
units: BoolInput,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** custom event handlers for inputs that need them */
|
||||||
|
export const handlers = {
|
||||||
|
only:
|
||||||
|
({ updateFunc, current }) =>
|
||||||
(path, part) => {
|
(path, part) => {
|
||||||
// if there's no part being set, it's a reset
|
// if there's no part being set, it's a reset
|
||||||
if (part === undefined) return updateFunc(path, part)
|
if (part === undefined) return updateFunc(path, part)
|
||||||
|
@ -37,18 +44,8 @@ export const OnlySettingInput = (props) => {
|
||||||
|
|
||||||
updateFunc(path, newParts)
|
updateFunc(path, newParts)
|
||||||
},
|
},
|
||||||
[updateFunc, current]
|
samm:
|
||||||
)
|
({ updateFunc, config, units }) =>
|
||||||
|
|
||||||
return <ListInput {...props} updateFunc={onlyUpdateFunc} />
|
|
||||||
}
|
|
||||||
|
|
||||||
/** An input for the samm setting */
|
|
||||||
export const SaMmSettingInput = (props) => {
|
|
||||||
const { updateFunc, units, config } = props
|
|
||||||
|
|
||||||
// the update function to switch the 'sa' setting along with samm
|
|
||||||
const mmUpdateFunc = useCallback(
|
|
||||||
(_path, newCurrent) => {
|
(_path, newCurrent) => {
|
||||||
// convert to millimeters if there's a value
|
// convert to millimeters if there's a value
|
||||||
newCurrent = newCurrent === undefined ? measurementAsMm(config.dflt, units) : newCurrent
|
newCurrent = newCurrent === undefined ? measurementAsMm(config.dflt, units) : newCurrent
|
||||||
|
@ -58,25 +55,8 @@ export const SaMmSettingInput = (props) => {
|
||||||
[['sa'], newCurrent],
|
[['sa'], newCurrent],
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
[updateFunc, units, config.dflt]
|
sabool:
|
||||||
)
|
({ updateFunc, samm }) =>
|
||||||
|
|
||||||
return (
|
|
||||||
<MmInput
|
|
||||||
{...{
|
|
||||||
...props,
|
|
||||||
updateFunc: mmUpdateFunc,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** An input for the sabool setting */
|
|
||||||
export const SaBoolSettingInput = (props) => {
|
|
||||||
const { updateFunc, samm } = props
|
|
||||||
|
|
||||||
// the update function to toggle the 'sa' setting based on 'sabool'
|
|
||||||
const saUpdateFunc = useCallback(
|
|
||||||
(_path, newCurrent) => {
|
(_path, newCurrent) => {
|
||||||
updateFunc([
|
updateFunc([
|
||||||
// update sabool to the new current
|
// update sabool to the new current
|
||||||
|
@ -85,16 +65,4 @@ export const SaBoolSettingInput = (props) => {
|
||||||
[['sa'], newCurrent ? samm : undefined],
|
[['sa'], newCurrent ? samm : undefined],
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
[updateFunc, samm]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BoolInput
|
|
||||||
{...{
|
|
||||||
...props,
|
|
||||||
name: 'sabool',
|
|
||||||
updateFunc: saUpdateFunc,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
import { ListValue, MmValue, PlainValue } from '../shared/values'
|
import { ListValue, MmValue, PlainValue } from '../shared/values'
|
||||||
|
|
||||||
export const RendererSettingValue = ListValue
|
const ScaleSettingValue = ({ current, config, changed }) => (
|
||||||
export const LocaleSettingValue = ListValue
|
|
||||||
export const CompleteSettingValue = ListValue
|
|
||||||
export const PaperlessSettingValue = ListValue
|
|
||||||
export const SaBoolSettingValue = ListValue
|
|
||||||
export const UnitsSettingValue = ListValue
|
|
||||||
|
|
||||||
export const MarginSettingValue = MmValue
|
|
||||||
export const SaMmSettingValue = MmValue
|
|
||||||
|
|
||||||
export const ScaleSettingValue = ({ current, config, changed }) => (
|
|
||||||
<PlainValue current={current} dflt={config.dflt} changed={changed} />
|
<PlainValue current={current} dflt={config.dflt} changed={changed} />
|
||||||
)
|
)
|
||||||
|
|
||||||
export const OnlySettingValue = ({ current, config }) => (
|
const OnlySettingValue = ({ current, config }) => (
|
||||||
<PlainValue
|
<PlainValue
|
||||||
current={current?.length}
|
current={current?.length}
|
||||||
dflt={config.parts.length}
|
dflt={config.parts.length}
|
||||||
changed={current !== undefined}
|
changed={current !== undefined}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const values = {
|
||||||
|
complete: ListValue,
|
||||||
|
locale: ListValue,
|
||||||
|
margin: MmValue,
|
||||||
|
only: OnlySettingValue,
|
||||||
|
paperless: ListValue,
|
||||||
|
sabool: ListValue,
|
||||||
|
samm: MmValue,
|
||||||
|
scale: ScaleSettingValue,
|
||||||
|
units: ListValue,
|
||||||
|
}
|
||||||
|
|
|
@ -1,67 +1,14 @@
|
||||||
// Components
|
// Components
|
||||||
import { OptionsIcon } from 'shared/components/icons.mjs'
|
import { OptionsIcon } from 'shared/components/icons.mjs'
|
||||||
import { optionsMenuStructure } from 'shared/utils.mjs'
|
import { optionsMenuStructure, optionType } from 'shared/utils.mjs'
|
||||||
import { optionType, formatMm } from 'shared/utils.mjs'
|
|
||||||
import {
|
import { values } from './values.mjs'
|
||||||
BoolInput,
|
import { inputs } from './inputs.mjs'
|
||||||
ConstantInput,
|
|
||||||
SliderInput,
|
|
||||||
DegInput,
|
|
||||||
ListInput,
|
|
||||||
PctInput,
|
|
||||||
} from '../shared/inputs.mjs'
|
|
||||||
import {
|
|
||||||
BoolOptionValue,
|
|
||||||
ConstantOptionValue,
|
|
||||||
CountOptionValue,
|
|
||||||
DegOptionValue,
|
|
||||||
ListOptionValue,
|
|
||||||
MmOptionValue,
|
|
||||||
PctOptionValue,
|
|
||||||
} from './values.mjs'
|
|
||||||
import { WorkbenchMenu } from '../shared/index.mjs'
|
import { WorkbenchMenu } from '../shared/index.mjs'
|
||||||
import { MenuItem } from '../shared/menu-item.mjs'
|
import { MenuItem } from '../shared/menu-item.mjs'
|
||||||
|
|
||||||
export const ns = ['design-options']
|
export const ns = ['design-options']
|
||||||
|
|
||||||
const PctOptionInput = (props) => {
|
|
||||||
const { config, settings, changed } = props
|
|
||||||
const currentOrDefault = changed ? props.current : config.dflt / 100
|
|
||||||
return (
|
|
||||||
<PctInput {...props}>
|
|
||||||
<div className="flex flex-row justify-around">
|
|
||||||
<span className={changed ? 'text-accent' : 'text-secondary'}>
|
|
||||||
{config.toAbs && settings.measurements
|
|
||||||
? formatMm(config.toAbs(currentOrDefault, settings))
|
|
||||||
: ' '}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</PctInput>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Facilitate lookup of the input component
|
|
||||||
const inputs = {
|
|
||||||
bool: BoolInput,
|
|
||||||
constant: ConstantInput,
|
|
||||||
count: SliderInput,
|
|
||||||
deg: DegInput,
|
|
||||||
list: ListInput,
|
|
||||||
mm: () => <span>FIXME: Mm options are deprecated. Please report this </span>,
|
|
||||||
pct: PctOptionInput,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Facilitate lookup of the value component
|
|
||||||
const values = {
|
|
||||||
bool: BoolOptionValue,
|
|
||||||
constant: ConstantOptionValue,
|
|
||||||
count: CountOptionValue,
|
|
||||||
deg: DegOptionValue,
|
|
||||||
list: ListOptionValue,
|
|
||||||
mm: MmOptionValue,
|
|
||||||
pct: PctOptionValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emojis for option groups :)
|
// Emojis for option groups :)
|
||||||
const emojis = {
|
const emojis = {
|
||||||
advanced: '🤓',
|
advanced: '🤓',
|
||||||
|
@ -77,11 +24,13 @@ const emojis = {
|
||||||
* @param {Object} options.settings core settings
|
* @param {Object} options.settings core settings
|
||||||
* @param {Object} options.rest the rest of the props
|
* @param {Object} options.rest the rest of the props
|
||||||
*/
|
*/
|
||||||
export const DesignOption = ({ config, settings, ...rest }) => {
|
const DesignOption = ({ config, settings, control, ...rest }) => {
|
||||||
const type = optionType(config)
|
const type = optionType(config)
|
||||||
const Input = inputs[type]
|
const Input = inputs[type]
|
||||||
const Value = values[type]
|
const Value = values[type]
|
||||||
const allowOverride = ['pct', 'count', 'deg'].includes(type)
|
const allowOverride = ['pct', 'count', 'deg'].includes(type)
|
||||||
|
const allowToggle =
|
||||||
|
(control > 3 && type === 'bool') || (type == 'list' && config.list.length === 2)
|
||||||
|
|
||||||
// Hide option?
|
// Hide option?
|
||||||
if (config?.hide || (typeof config?.hide === 'function' && config.hide(settings))) return null
|
if (config?.hide || (typeof config?.hide === 'function' && config.hide(settings))) return null
|
||||||
|
@ -90,10 +39,12 @@ export const DesignOption = ({ config, settings, ...rest }) => {
|
||||||
<MenuItem
|
<MenuItem
|
||||||
{...{
|
{...{
|
||||||
config,
|
config,
|
||||||
|
control,
|
||||||
...rest,
|
...rest,
|
||||||
Input,
|
Input,
|
||||||
Value,
|
Value,
|
||||||
allowOverride,
|
allowOverride,
|
||||||
|
allowToggle,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { formatMm } from 'shared/utils.mjs'
|
||||||
|
import {
|
||||||
|
BoolInput,
|
||||||
|
ConstantInput,
|
||||||
|
SliderInput,
|
||||||
|
DegInput,
|
||||||
|
ListInput,
|
||||||
|
PctInput,
|
||||||
|
} from '../shared/inputs.mjs'
|
||||||
|
|
||||||
|
const PctOptionInput = (props) => {
|
||||||
|
const { config, settings, changed } = props
|
||||||
|
const currentOrDefault = changed ? props.current : config.dflt / 100
|
||||||
|
return (
|
||||||
|
<PctInput {...props}>
|
||||||
|
<div className="flex flex-row justify-around">
|
||||||
|
<span className={changed ? 'text-accent' : 'text-secondary'}>
|
||||||
|
{config.toAbs && settings.measurements
|
||||||
|
? formatMm(config.toAbs(currentOrDefault, settings))
|
||||||
|
: ' '}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</PctInput>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Facilitate lookup of the input component
|
||||||
|
export const inputs = {
|
||||||
|
bool: BoolInput,
|
||||||
|
constant: ConstantInput,
|
||||||
|
count: SliderInput,
|
||||||
|
deg: DegInput,
|
||||||
|
list: ListInput,
|
||||||
|
mm: () => <span>FIXME: Mm options are deprecated. Please report this </span>,
|
||||||
|
pct: PctOptionInput,
|
||||||
|
}
|
|
@ -13,9 +13,6 @@ export const PctOptionValue = ({ config, current, settings, changed }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Displays a boolean value */
|
|
||||||
export const BoolOptionValue = BoolValue
|
|
||||||
|
|
||||||
/** Displays a count value*/
|
/** Displays a count value*/
|
||||||
export const CountOptionValue = ({ config, current, changed }) => (
|
export const CountOptionValue = ({ config, current, changed }) => (
|
||||||
<PlainValue {...{ current, changed, dflt: config.count }} />
|
<PlainValue {...{ current, changed, dflt: config.count }} />
|
||||||
|
@ -40,3 +37,14 @@ export const MmOptionValue = () => (
|
||||||
export const ConstantOptionValue = () => (
|
export const ConstantOptionValue = () => (
|
||||||
<span className="text-error">FIXME: No ConstantOptionvalue implemented</span>
|
<span className="text-error">FIXME: No ConstantOptionvalue implemented</span>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Facilitate lookup of the value component
|
||||||
|
export const values = {
|
||||||
|
bool: BoolValue,
|
||||||
|
constant: ConstantOptionValue,
|
||||||
|
count: CountOptionValue,
|
||||||
|
deg: DegOptionValue,
|
||||||
|
list: ListOptionValue,
|
||||||
|
mm: MmOptionValue,
|
||||||
|
pct: PctOptionValue,
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useCallback } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { round, measurementAsMm, measurementAsUnits, formatFraction128 } from 'shared/utils.mjs'
|
import { round, measurementAsMm, measurementAsUnits, formatFraction128 } from 'shared/utils.mjs'
|
||||||
import { ChoiceButton } from 'shared/components/choice-button.mjs'
|
import { ChoiceButton } from 'shared/components/choice-button.mjs'
|
||||||
|
|
||||||
|
@ -35,31 +35,55 @@ const EditCount = (props) => (
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook to get the change handler for an input.
|
* A hook to get the change handler for an input.
|
||||||
* Also sets the reset function on a parent component
|
|
||||||
* @param {Number|String|Boolean} options.dflt the default value for the input
|
* @param {Number|String|Boolean} options.dflt the default value for the input
|
||||||
* @param {Function} options.updateFunc the onChange
|
* @param {Function} options.updateFunc the onChange
|
||||||
* @param {string} options.name the name of the property being changed
|
* @param {string} options.name the name of the property being changed
|
||||||
* @param {Function} options.setReset the setReset function passed from the parent component
|
* @return the change handler for the input
|
||||||
* @return {ret.handleChange} the change handler for the input
|
|
||||||
*/
|
*/
|
||||||
const useSharedHandlers = ({ dflt, updateFunc, name, setReset }) => {
|
const useSharedHandlers = ({ dflt, updateFunc, name }) => {
|
||||||
const reset = useCallback(() => updateFunc(name), [updateFunc, name])
|
return useCallback(
|
||||||
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(newCurrent) => {
|
(newCurrent) => {
|
||||||
if (newCurrent === dflt) reset()
|
if (newCurrent === dflt) newCurrent = undefined
|
||||||
else {
|
else {
|
||||||
updateFunc(name, newCurrent)
|
updateFunc(name, newCurrent)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dflt, updateFunc, name, reset]
|
[dflt, updateFunc, name]
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
/** get the configuration that allows a boolean value to use the list input */
|
||||||
if (typeof setReset === 'function') setReset(() => reset)
|
const useBoolConfig = (name, config) => {
|
||||||
}, [reset, setReset])
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
list: [false, true],
|
||||||
|
choiceTitles: {
|
||||||
|
false: `${name}No`,
|
||||||
|
true: `${name}Yes`,
|
||||||
|
},
|
||||||
|
valueTitles: {
|
||||||
|
false: 'no',
|
||||||
|
true: 'yes',
|
||||||
|
},
|
||||||
|
...config,
|
||||||
|
}),
|
||||||
|
[name, config]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return { handleChange, reset }
|
/** a toggle input for list/boolean values */
|
||||||
|
export const ListToggle = ({ config, changed, updateFunc, name }) => {
|
||||||
|
const boolConfig = useBoolConfig(name, config)
|
||||||
|
const handleChange = useSharedHandlers({ dflt: boolConfig.dflt, updateFunc, name })
|
||||||
|
|
||||||
|
const dfltIndex = boolConfig.list.indexOf(boolConfig.dflt)
|
||||||
|
|
||||||
|
const doToggle = () =>
|
||||||
|
handleChange(boolConfig.list[changed ? dfltIndex : Math.abs(dfltIndex - 1)])
|
||||||
|
|
||||||
|
const checked = boolConfig.dflt == false ? changed : !changed
|
||||||
|
|
||||||
|
return <input type="checkbox" className="toggle" checked={checked} onChange={doToggle} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,14 +94,12 @@ const useSharedHandlers = ({ dflt, updateFunc, name, setReset }) => {
|
||||||
* @param {Function} options.updateFunc the function called by the event handler to update the value
|
* @param {Function} options.updateFunc the function called by the event handler to update the value
|
||||||
* @param {Boolean} options.compact include descriptions with the list items?
|
* @param {Boolean} options.compact include descriptions with the list items?
|
||||||
* @param {Function} options.t translation function
|
* @param {Function} options.t translation function
|
||||||
* @param {Function} options.setReset a setter for the reset function on the parent component
|
|
||||||
*/
|
*/
|
||||||
export const ListInput = ({ name, config, current, updateFunc, compact = false, t, setReset }) => {
|
export const ListInput = ({ name, config, current, updateFunc, compact = false, t, changed }) => {
|
||||||
const { handleChange } = useSharedHandlers({
|
const handleChange = useSharedHandlers({
|
||||||
dflt: config.dflt,
|
dflt: config.dflt,
|
||||||
updateFunc,
|
updateFunc,
|
||||||
name,
|
name,
|
||||||
setReset,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -90,7 +112,7 @@ export const ListInput = ({ name, config, current, updateFunc, compact = false,
|
||||||
key={entry}
|
key={entry}
|
||||||
title={t(`${titleKey}${compact ? '' : '.t'}`)}
|
title={t(`${titleKey}${compact ? '' : '.t'}`)}
|
||||||
color={entry === config.dflt ? 'primary' : 'accent'}
|
color={entry === config.dflt ? 'primary' : 'accent'}
|
||||||
active={current === entry}
|
active={changed ? current === entry : entry === config.dflt}
|
||||||
onClick={() => handleChange(entry)}
|
onClick={() => handleChange(entry)}
|
||||||
>
|
>
|
||||||
{compact ? null : t(`${titleKey}.d`)}
|
{compact ? null : t(`${titleKey}.d`)}
|
||||||
|
@ -103,19 +125,8 @@ export const ListInput = ({ name, config, current, updateFunc, compact = false,
|
||||||
|
|
||||||
/** A boolean version of {@see ListInput} that sets up the necessary configuration */
|
/** A boolean version of {@see ListInput} that sets up the necessary configuration */
|
||||||
export const BoolInput = (props) => {
|
export const BoolInput = (props) => {
|
||||||
const boolConfig = {
|
const { name, config } = props
|
||||||
list: [0, 1],
|
const boolConfig = useBoolConfig(name, config)
|
||||||
choiceTitles: {
|
|
||||||
0: `${props.name}No`,
|
|
||||||
1: `${props.name}Yes`,
|
|
||||||
},
|
|
||||||
valueTitles: {
|
|
||||||
0: 'no',
|
|
||||||
1: 'yes',
|
|
||||||
},
|
|
||||||
dflt: props.config.dflt ? 1 : 0,
|
|
||||||
...props.config,
|
|
||||||
}
|
|
||||||
|
|
||||||
return <ListInput {...props} config={boolConfig} />
|
return <ListInput {...props} config={boolConfig} />
|
||||||
}
|
}
|
||||||
|
@ -146,7 +157,7 @@ export const SliderInput = ({
|
||||||
changed,
|
changed,
|
||||||
}) => {
|
}) => {
|
||||||
const { max, min } = config
|
const { max, min } = config
|
||||||
const { handleChange } = useSharedHandlers({
|
const handleChange = useSharedHandlers({
|
||||||
current,
|
current,
|
||||||
dflt: config.dflt,
|
dflt: config.dflt,
|
||||||
updateFunc,
|
updateFunc,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ClearIcon, HelpIcon, EditIcon } from 'shared/components/icons.mjs'
|
import { ClearIcon, HelpIcon, EditIcon } from 'shared/components/icons.mjs'
|
||||||
import { Collapse } from 'shared/components/collapse.mjs'
|
import { Collapse } from 'shared/components/collapse.mjs'
|
||||||
import { useState, useMemo } from 'react'
|
import { useState, useMemo } from 'react'
|
||||||
|
import { ListToggle } from './inputs.mjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if a value is different from its default
|
* Check to see if a value is different from its default
|
||||||
|
@ -10,7 +11,7 @@ import { useState, useMemo } from 'react'
|
||||||
*/
|
*/
|
||||||
export const wasChanged = (current, config) => {
|
export const wasChanged = (current, config) => {
|
||||||
if (typeof current === 'undefined') return false
|
if (typeof current === 'undefined') return false
|
||||||
if (current === config.dflt) return false
|
if (current == config.dflt) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -65,27 +66,26 @@ export const MenuItem = ({
|
||||||
Input,
|
Input,
|
||||||
Value,
|
Value,
|
||||||
allowOverride = false,
|
allowOverride = false,
|
||||||
|
allowToggle = false,
|
||||||
control = Infinity,
|
control = Infinity,
|
||||||
}) => {
|
}) => {
|
||||||
// state for knowing whether the override input should be shown
|
// state for knowing whether the override input should be shown
|
||||||
const [override, setOverride] = useState(false)
|
const [override, setOverride] = useState(false)
|
||||||
// store the reset function in state because the Input may set a custom one
|
|
||||||
const [reset, setReset] = useState(() => () => updateFunc(name))
|
|
||||||
|
|
||||||
// generate properties to pass to the Input
|
// generate properties to pass to the Input
|
||||||
const drillProps = useMemo(
|
const drillProps = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
name,
|
name,
|
||||||
config,
|
config,
|
||||||
|
control,
|
||||||
current,
|
current,
|
||||||
updateFunc,
|
updateFunc,
|
||||||
t,
|
t,
|
||||||
changed,
|
changed,
|
||||||
override,
|
override,
|
||||||
setReset, // allow setting of the reset function
|
|
||||||
...passProps,
|
...passProps,
|
||||||
}),
|
}),
|
||||||
[name, config, current, updateFunc, t, changed, override, setReset, passProps]
|
[name, config, current, updateFunc, t, changed, override, passProps, control]
|
||||||
)
|
)
|
||||||
|
|
||||||
// don't render if this item is more advanced than the user has chosen to see
|
// don't render if this item is more advanced than the user has chosen to see
|
||||||
|
@ -113,13 +113,13 @@ export const MenuItem = ({
|
||||||
<EditIcon className={`w-6 h-6 ${override ? 'bg-base-100 text-accent rounded' : ''}`} />
|
<EditIcon className={`w-6 h-6 ${override ? 'bg-base-100 text-accent rounded' : ''}`} />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
if (changed) {
|
if (changed && !allowToggle) {
|
||||||
const ResetButton = ({ open }) => (
|
const ResetButton = ({ open }) => (
|
||||||
<button
|
<button
|
||||||
className={open ? openButtonClass : 'btn btn-accent'}
|
className={open ? openButtonClass : 'btn btn-accent'}
|
||||||
onClick={(evt) => {
|
onClick={(evt) => {
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
reset()
|
updateFunc(name)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ClearIcon />
|
<ClearIcon />
|
||||||
|
@ -129,6 +129,10 @@ export const MenuItem = ({
|
||||||
openButtons.push(<ResetButton open key="clear" />)
|
openButtons.push(<ResetButton open key="clear" />)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allowToggle) {
|
||||||
|
buttons.push(<ListToggle {...{ config, changed, updateFunc, name }} />)
|
||||||
|
}
|
||||||
|
|
||||||
// props to pass to the ItemTitle
|
// props to pass to the ItemTitle
|
||||||
const titleProps = { name, t, current: <Value {...drillProps} />, emoji: config.emoji }
|
const titleProps = { name, t, current: <Value {...drillProps} />, emoji: config.emoji }
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ export const DraftMenu = ({
|
||||||
DynamicDocs,
|
DynamicDocs,
|
||||||
inspector = false,
|
inspector = false,
|
||||||
}) => {
|
}) => {
|
||||||
// Default control level is 2 (in case people are not logged in)
|
const control = account.control
|
||||||
const control = account.control || 2
|
|
||||||
const menuProps = {
|
const menuProps = {
|
||||||
design,
|
design,
|
||||||
patternConfig,
|
patternConfig,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue