From 58cb94230037e3b8b6f49f2ac48f963fb8d4203f Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Fri, 15 May 2026 22:42:44 +0000 Subject: [PATCH 1/2] docs: add documentation for custom attribute types (issue #118) Document how to add custom attribute types (selects, radios, checkboxes) to the attribute pane programmatically. Covers: - Value type to input type mapping (string, number, boolean, array) - Select dropdown attributes via control definition or config.attrs - Programmatic attribute addition via EditPanel.addAttribute() - Controlling attribute visibility with disabledAttrs/lockedAttrs - Complete example with multiple attribute types --- docs/controls/custom-attribute-types.md | 219 ++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 docs/controls/custom-attribute-types.md diff --git a/docs/controls/custom-attribute-types.md b/docs/controls/custom-attribute-types.md new file mode 100644 index 00000000..00addfb7 --- /dev/null +++ b/docs/controls/custom-attribute-types.md @@ -0,0 +1,219 @@ +# Custom Attribute Types + +By default, attributes in the editor's attribute pane are rendered as text inputs. Formeo supports several attribute input types that are automatically detected from the attribute value type, and you can also provide dropdown options for attributes. + +## Supported Attribute Input Types + +Formeo automatically maps JavaScript value types to editor input types: + +| JavaScript Value Type | Editor Input | Example | +|---|---|---| +| `string` | Text input | `type: 'text'` | +| `number` | Number input | `maxLength: 100` | +| `boolean` | Checkbox | `required: false` | +| `array` of options | Select dropdown | See below | + +## Select Dropdown Attributes + +To render an attribute as a select dropdown, define its value as an array of option objects with `label`, `value`, and `selected` properties. + +### Method 1: Define in Control Definition + +When creating a custom control, set the attribute value to an array of options: + +```javascript +const customControl = { + tag: 'div', + attrs: { + // This renders as a text input + className: '', + + // This renders as a select dropdown + alignment: [ + { label: 'Left', value: 'left', selected: true }, + { label: 'Center', value: 'center', selected: false }, + { label: 'Right', value: 'right', selected: false }, + ], + + // This renders as a checkbox + visible: true, + }, + config: { + label: 'Custom Element', + }, + meta: { + group: 'html', + id: 'custom-element', + icon: 'custom', + }, +} + +const formeoOptions = { + controls: { + elements: [customControl], + }, +} + +const formeo = new FormeoEditor(formeoOptions) +``` + +The built-in **header** control uses this pattern for its `tag` attribute (h1, h2, h3, h4, h5): + +```javascript +// From header.js +attrs: { + tag: headerTags.map((tag, index) => ({ + label: tag.toUpperCase(), + value: tag, + selected: !index, // first item selected by default + })), + className: '', +}, +``` + +### Method 2: Use config.attrs for Dropdown Options + +You can also provide dropdown options through the `config` option. Set `config.attrs[attrName]` to an array of options, and the editor will render that attribute as a select dropdown instead of a text input. + +```javascript +const formeoOptions = { + config: { + fields: { + // Apply to all text-input fields + 'text-input': { + attrs: { + // Make the 'type' attribute a dropdown instead of a text input + type: [ + { label: 'Text', value: 'text', selected: true }, + { label: 'Email', value: 'email', selected: false }, + { label: 'Password', value: 'password', selected: false }, + { label: 'Number', value: 'number', selected: false }, + ], + }, + }, + }, + }, +} + +const formeo = new FormeoEditor(formeoOptions) +``` + +## Radio Button Attributes + +Boolean attributes in the `options` panel (like `selected` on radio group or checkbox group options) are automatically rendered as radio buttons instead of checkboxes. This is handled internally by Formeo. + +## Programmatic Attribute Addition + +You can add attributes programmatically using the `addAttribute` method on the edit panel: + +```javascript +// Get the field component and add a new attribute +const field = Components.fields.get(fieldId) +const editPanel = field.editPanels.get('attrs') + +// Add a simple text attribute +editPanel.addAttribute('data-custom', 'some value') + +// Add a boolean attribute (renders as checkbox) +editPanel.addAttribute('disabled', false) + +// Add a number attribute (renders as number input) +editPanel.addAttribute('data-max', 100) +``` + +## Controlling Attribute Visibility + +Use the `config` option to control which attributes are visible, disabled, or locked: + +```javascript +const formeoOptions = { + config: { + fields: { + 'text-input': { + // Hide specific attributes from the panel + panels: { + attrs: { + disabled: ['type'], // hides the type attribute + locked: ['name'], // prevents removal of the name attribute + }, + }, + }, + }, + }, +} +``` + +You can also use `disabledAttrs` and `lockedAttrs` in the control definition: + +```javascript +const customControl = { + tag: 'input', + attrs: { + type: 'email', + name: 'email', + }, + config: { + label: 'Email Input', + disabledAttrs: ['type'], // user cannot edit the type + lockedAttrs: ['name'], // user cannot remove the name attribute + }, + meta: { + group: 'common', + id: 'email-input', + icon: 'email', + }, +} +``` + +## Complete Example: Custom Control with Multiple Attribute Types + +```javascript +const richControl = { + tag: 'div', + attrs: { + // Text input + className: '', + + // Select dropdown + variant: [ + { label: 'Default', value: 'default', selected: true }, + { label: 'Primary', value: 'primary', selected: false }, + { label: 'Secondary', value: 'secondary', selected: false }, + ], + + // Checkbox + collapsible: false, + + // Number input + maxLines: 5, + }, + config: { + label: 'Rich Block', + disabledAttrs: [], + lockedAttrs: ['variant'], + }, + meta: { + group: 'html', + id: 'rich-block', + icon: 'block', + }, + content: 'Rich block content', +} + +const formeoOptions = { + controls: { + elements: [richControl], + elementOrder: { + html: ['rich-block', 'header', 'paragraph', 'divider'], + }, + }, +} + +const formeo = new FormeoEditor(formeoOptions) +``` + +## See Also + +- [Controls](../controls/README.md) - Overview of controls and control groups +- [Control Options](../options/controls/README.md) - Configure the control panel +- [Config Option](../options/config/README.md) - Fine-tune the editor UI From b6cceea257b074f96856e29bd1c9d4ce11899dfc Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Fri, 15 May 2026 16:08:59 -0700 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/controls/custom-attribute-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/controls/custom-attribute-types.md b/docs/controls/custom-attribute-types.md index 00addfb7..97490cd3 100644 --- a/docs/controls/custom-attribute-types.md +++ b/docs/controls/custom-attribute-types.md @@ -57,7 +57,7 @@ const formeoOptions = { const formeo = new FormeoEditor(formeoOptions) ``` -The built-in **header** control uses this pattern for its `tag` attribute (h1, h2, h3, h4, h5): +The built-in **header** control uses this pattern for its `tag` attribute (h1, h2, h3, h4): ```javascript // From header.js