Skip to content

Commit

Permalink
[TASK] add video and embed fields, add NESTED_COMMON_FIELDS types, mo…
Browse files Browse the repository at this point in the history
…re typings
  • Loading branch information
dmh committed Aug 31, 2023
1 parent 5dfaf16 commit 017a6d5
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 39 deletions.
8 changes: 6 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import {
text,
link,
richtext,
url
url,
video,
embed
} from './lib/content-tab-fields.js'

/**
Expand All @@ -46,7 +48,9 @@ const moduleFields = {
gradient,
backgroundimage,
border,
textalignment
textalignment,
video,
embed
}
/**
* #### Theme fields entry point
Expand Down
73 changes: 72 additions & 1 deletion lib/content-tab-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,75 @@ function url (label, name, fields) {
return { ...contentOptions, ...otherOptions }
}

export { text, link, richtext, url }
/**
* #### Video fields provide content editors with a place to add HubSpot Video to their module content without the need of using rich text fields.
* `only_content_tab`
*
* Some parameters have `default` values, `OMIT` such parameters if you don't want to override them.
* @example
* fi.video('label', 'name', {...options if needed})
* @memberof Fields
* @param {string} label The text the content creator sees describing the field. May contain spaces.
* @param {string} name Field/HubL variable name, which you'll reference when incorporating the field and its values in the module or theme. `Cannot contain spaces or special characters!`
* @param {Object} [fields]
* @param {boolean} [fields.resizable=true] `true` Whether the video is resizable
* @param {boolean} [fields.show_preview=true] `true` Whether the video is previewable
* @param {boolean} [fields.show_advanced_options=true] `true` Whether the video is advanced options
* @param {Object} [fields.default] Default object --> It's generally a good idea to skip setting the `default` object, as it should be configured by the editor, not the developer
* @param {EDITOR_OPTIONS} [fields.editor_options] Editor options group.
* @param {DISPLAY_CONDITIONS} [fields.display_conditions] Display conditions group.
* @param {REPEATER_OPTIONS} [fields.repeater_options] Repeater options. Keep `occurrence` object empty to just enable a feature. `repeater_options: {occurrence: {}}`
* @param {REPEATER_OPTIONS_DEFAULT} [fields.repeater_options_default] Repeater options with predefined repeated fields and `default` values for each field.
* @returns {COMMON_FIELDS}
*/
function video (label, name, fields) {
const contentOptions = {}
contentOptions.resizable = fields?.resizable ?? true
contentOptions.show_preview = fields?.show_preview ?? true
contentOptions.show_advanced_options = fields?.show_advanced_options ?? true
contentOptions.default = fields?.default ?? {}

const otherOptions = initField(label, name, 'videoplayer', fields)
return { ...contentOptions, ...otherOptions }
}

/**
* #### Embed fields allow the user to add a URL from an oEmbed-enabled site or paste in an embed code from another site.
* `only_content_tab`
*
* Some parameters have `default` values, `OMIT` such parameters if you don't want to override them.
* @example
* fi.embed('label', 'name', {...options if needed})
* @memberof Fields
* @param {string} label The text the content creator sees describing the field. May contain spaces.
* @param {string} name Field/HubL variable name, which you'll reference when incorporating the field and its values in the module or theme. `Cannot contain spaces or special characters!`
* @param {Object} [fields]
* @param {Array<'oembed'|'html'>} [fields.supported_source_types=all] `all` Array of source types that are supported by the field.
* @param {Array<'photo'|'video'|'link'|'rich'>} [fields.supported_oembed_types=all] `all` Array of oEmbed types that are supported by the field.
* @param {boolean} [fields.resizable=true] `true` Whether the embed is resizable
* @param {boolean} [fields.show_preview=true] `true` Whether the embed is previewable
* @param {Array<string>} [fields.supported_media_bridge_providers] Array of provider IDs that determine which Media Bridge providers are available to select content from.
* @param {Object} [fields.default] Default object --> It's generally a good idea to skip setting the `default` object, as it should be configured by the editor, not the developer
* @param {EDITOR_OPTIONS} [fields.editor_options] Editor options group.
* @param {DISPLAY_CONDITIONS} [fields.display_conditions] Display conditions group.
* @param {REPEATER_OPTIONS} [fields.repeater_options] Repeater options. Keep `occurrence` object empty to just enable a feature. `repeater_options: {occurrence: {}}`
* @param {REPEATER_OPTIONS_DEFAULT} [fields.repeater_options_default] Repeater options with predefined repeated fields and `default` values for each field.
* @returns {COMMON_FIELDS}
*/
function embed (label, name, fields) {
const contentOptions = {}
contentOptions.supported_source_types = fields?.supported_source_types ?? ['oembed', 'html']
contentOptions.supported_oembed_types = fields?.supported_oembed_types ?? ['photo', 'video', 'link', 'rich']
contentOptions.resizable = fields?.resizable ?? true
contentOptions.show_preview = fields?.show_preview ?? true
contentOptions.supported_media_bridge_providers = fields?.supported_media_bridge_providers ?? []
const defaultObj = {
source_type: 'oembed'
}
contentOptions.default = { ...defaultObj, ...fields?.default }

const otherOptions = initField(label, name, 'embed', fields)
return { ...contentOptions, ...otherOptions }
}

export { text, link, richtext, url, video, embed }
12 changes: 6 additions & 6 deletions lib/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ function choice (label, name, fields) {
* @param {Object} [fields]
* @param {Boolean} [fields.show_opacity=true] `true` Sets whether opacity input is shown. true: the opacity input is shown. false: the opacity input is hidden. If left undefined, opacity input will not display in email modules, but will display in other module types.
* @param {Object} [fields.default] Sets the default selected color and opacity --> It's generally a good idea to skip setting the `default` object, as it should be configured by the editor, not the developer.
* @param {String} [fields.default.color] The default color
* @param {Number} [fields.default.opacity] The default opacity
* @param {string?} [fields.default.color] The default color
* @param {number?} [fields.default.opacity] The default opacity
* @param {EDITOR_OPTIONS} [fields.editor_options] Editor options group.
* @param {DISPLAY_CONDITIONS} [fields.display_conditions] Display conditions group.
* @param {REPEATER_OPTIONS} [fields.repeater_options] Repeater options. Keep `occurrence` object empty to just enable a feature. `repeater_options: {occurrence: {}}`
Expand Down Expand Up @@ -239,13 +239,13 @@ function color (label, name, fields) {
* @param {Object} [fields]
* @param {Boolean} [fields.load_external_fonts=true] `true` HubSpot automatically loads the selected web font to the page if the font is selected and referenced by HubL in a stylesheet or in a module. Set this to false, if you are already loading the font to the page, that way the font won't load twice.
* @param {Object} [fields.default] Font default object --> It's generally a good idea to skip setting the `default` object, as it should be configured by the editor, not the developer
* @param {String} fields.default.font Default family name of the font
* @param {string} [fields.default.font] Default family name of the font
* @param {'sans-serif'|'serif'|null} [fields.default.fallback] Default fallback font
* @param {'100'|'200'|'300'|'regular'|'500'|'600'|'700'|'800'|'900'|'100italic'|'200italic'|'300italic'|'400italic'|'500italic'|'600italic'|'700italic'|'800italic'|'900italic'|null} [fields.default.variant] Font variant
* @param {'GOOGLE'|'DEFAULT'} fields.default.font_set Default font set
* @param {'GOOGLE'|'DEFAULT'} [fields.default.font_set] Default font set
* @param {TEXT_STYLES} [fields.default.styles] Default text styles
* @param {Number} [fields.default.size] Default font size
* @param {String} [fields.default.color] Default font color
* @param {number} [fields.default.size] Default font size
* @param {string?} [fields.default.color] Default font color
* @param {'rem'|'px'|'em'|'rem'|'%'|'ex'|'ch'} [fields.default.size_unit] Default font size unit
* @param {EDITOR_OPTIONS} [fields.editor_options] Editor options group.
* @param {DISPLAY_CONDITIONS} [fields.display_conditions] Display conditions group.
Expand Down
9 changes: 5 additions & 4 deletions lib/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { EditorOptions, DisplayConditions, RepeaterOptions, RepeaterOptionsDefau
* @typedef {TYPES.REPEATER_OPTIONS} REPEATER_OPTIONS {@link REPEATER_OPTIONS}
* @typedef {TYPES.REPEATER_OPTIONS_DEFAULT} REPEATER_OPTIONS_DEFAULT {@link REPEATER_OPTIONS_DEFAULT}
* @typedef {TYPES.COMMON_FIELDS} COMMON_FIELDS {@link COMMON_FIELDS}
* @typedef {TYPES.NESTED_COMMON_FIELDS} NESTED_COMMON_FIELDS {@link NESTED_COMMON_FIELDS}
*/

// *************
Expand All @@ -32,7 +33,7 @@ import { EditorOptions, DisplayConditions, RepeaterOptions, RepeaterOptionsDefau
* @param {DISPLAY_CONDITIONS} [fields.display_conditions] Display conditions group.
* @param {REPEATER_OPTIONS} [fields.repeater_options] Repeater options. Keep `occurrence` object empty to just enable a feature. `repeater_options: {occurrence: {}}`
* @param {REPEATER_OPTIONS_DEFAULT} [fields.repeater_options_default] Repeater options with predefined repeated fields and `default` values for each field.
* @param {Array<COMMON_FIELDS>} childrens
* @param {Array<NESTED_COMMON_FIELDS>} childrens
* @returns {COMMON_FIELDS}
*/
function group (label, name, fields, ...childrens) {
Expand All @@ -49,7 +50,7 @@ function group (label, name, fields, ...childrens) {
groupOptions.expanded = fields?.expanded ?? false
childrens.forEach(element => {
if (Array.isArray(element)) {
requiredFields.children?.push(...element)
requiredFields.children?.push(...element.flat(3))
} else {
requiredFields.children?.push(element)
}
Expand All @@ -71,7 +72,7 @@ function group (label, name, fields, ...childrens) {
* styleGroup(
* fi.alignment('alignment', 'Alignment')
* )
* @param {Array<COMMON_FIELDS>} childrens
* @param {Array<NESTED_COMMON_FIELDS>} childrens
* @returns {COMMON_FIELDS}
*/
function styleGroup (...childrens) {
Expand All @@ -87,7 +88,7 @@ function styleGroup (...childrens) {
}
childrens.forEach(element => {
if (Array.isArray(element)) {
baseFields.children?.push(...element)
baseFields.children?.push(...element.flat(3))
} else {
baseFields.children?.push(element)
}
Expand Down
29 changes: 15 additions & 14 deletions lib/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import path from 'node:path'
/**
* @ignore
* @typedef {TYPES.COMMON_FIELDS} COMMON_FIELDS {@link COMMON_FIELDS}
* @typedef {TYPES.NESTED_COMMON_FIELDS} NESTED_COMMON_FIELDS {@link NESTED_COMMON_FIELDS}
*/

/**
Expand All @@ -14,21 +15,21 @@ import path from 'node:path'
* @param {string} [prefix] prefix
* @returns {Array<COMMON_FIELDS>} portal name|names
*/
function addIdToObjects (array, prefix = '') {
array.forEach(obj => {
const id = prefix ? `${prefix}.${obj.name}` : obj.name
obj.id = id
if ('children' in obj && Array.isArray(obj.children)) {
addIdToObjects(obj.children, id)
}
})
return array
}
// function addIdToObjects (array, prefix = '') {
// array.forEach(obj => {
// const id = prefix ? `${prefix}.${obj.name}` : obj.name
// obj.id = id
// if ('children' in obj && Array.isArray(obj.children)) {
// addIdToObjects(obj.children, id)
// }
// })
// return array
// }

/**
* #### Initialize and return an array of fields object from fields.js
* Combine all the fields and groups objects into one array, and return it.
* @param {Array<COMMON_FIELDS|COMMON_FIELDS[]>} fields
* @param {Array<NESTED_COMMON_FIELDS>} fields
* @returns {COMMON_FIELDS[]}
* @example
* \/* eslint-disable no-unused-vars *\/
Expand All @@ -51,15 +52,15 @@ function addIdToObjects (array, prefix = '') {
*/
function init (...fields) {
/** @type {COMMON_FIELDS[]} */
let correctedFields = []
const correctedFields = []
fields.forEach(element => {
if (Array.isArray(element)) {
correctedFields.push(...element)
correctedFields.push(...element.flat(3))
} else {
correctedFields.push(element)
}
})
correctedFields = addIdToObjects(correctedFields)
// correctedFields = addIdToObjects(correctedFields)
return correctedFields
}

Expand Down
8 changes: 4 additions & 4 deletions lib/style-tab-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,28 +186,28 @@ function backgroundimage (label, name, fields) {
* @param {Object} [fields.default] Border default object --> It's generally a good idea to skip setting the `default` object, as it should be configured by the editor, not the developer
* @param {Object} [fields.default.top]
* @param {Object} fields.default.top.width
* @param {number} fields.default.top.width.value
* @param {number?} fields.default.top.width.value
* @param {'px'} fields.default.top.width.units
* @param {number} fields.default.top.opacity
* @param {'solid'|'double'|'dotted'|'dashed'} fields.default.top.style
* @param {string} fields.default.top.color
* @param {Object} [fields.default.bottom]
* @param {Object} fields.default.bottom.width
* @param {number} fields.default.bottom.width.value
* @param {number?} fields.default.bottom.width.value
* @param {'px'} fields.default.bottom.width.units
* @param {number} fields.default.bottom.opacity
* @param {'solid'|'double'|'dotted'|'dashed'} fields.default.bottom.style
* @param {string} fields.default.bottom.color
* @param {Object} [fields.default.left]
* @param {Object} fields.default.left.width
* @param {number} fields.default.left.width.value
* @param {number?} fields.default.left.width.value
* @param {'px'} fields.default.left.width.units
* @param {number} fields.default.left.opacity
* @param {'solid'|'double'|'dotted'|'dashed'} fields.default.left.style
* @param {string} fields.default.left.color
* @param {Object} [fields.default.right]
* @param {Object} fields.default.right.width
* @param {number} fields.default.right.width.value
* @param {number?} fields.default.right.width.value
* @param {'px'} fields.default.right.width.units
* @param {number} fields.default.right.opacity
* @param {'solid'|'double'|'dotted'|'dashed'} fields.default.right.style
Expand Down
47 changes: 43 additions & 4 deletions lib/types/types.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* #### Inherited values
* @typedef {any} INHERITED_VALUES
* @property {string} [color]
*/

/**
* #### HubSpot module editor options
* @typedef {Object} EDITOR_OPTIONS
Expand All @@ -6,23 +12,52 @@
* @property {string} [help_text] Text that displays in the editor within a tooltip on hover to assist the content creator (limit 300 characters). Best used for information that is supplementary but not required to use the field. You can include the following HTML tags (other tags will be ignored on render): a, b, br, em, i, p, small, strong, span.
* @property {string} [inline_help_text] Text that displays inline below field's label (limit 400 characters). Best used for information required to use the field. You can include the following HTML tags (other tags will be ignored on render): a, b, br, em, i, p, small, strong, span.
* @property {null|'half_width'} [display_width=full_width] `full_width` By default, fields are full-width in the editor.
* @property {Object} [inherited_value]
* @property {INHERITED_VALUES} [inherited_value.property_value_paths]
*/

/**
* #### Hidden subfields properties
* @typedef {Object} HIDDEN_SUBFIELDS
* @property {boolean} [margin]
* @property {boolean} [padding]
* @property {boolean} [bold]
* @property {boolean} [italic]
* @property {boolean} [underline]
* @property {boolean} [color]
* @property {boolean} [size]
*/

/**
* #### Advanced visibility criteria
* @typedef {Object} ADVANCED_VISIBILITY_CRITERIA
* @property {string} [controlling_field_path] The path of the field that controls the display condition.
* @property {string} [controlling_value_regex] The value in the controlling field that needs to be met to display the field.
* @property {'NOT_EQUAL'|'EQUAL'|'EMPTY'|'NOT_EMPTY'|'MATCHES_REGEX'} [operator] The operator that defines how the `controlling_value_regex` value needs to be met.
* @property {?string} [property] Sets visibility based on a specific property of the target field. For example, you can enable visibility when an image field's src property is equal to a specific value. By default, if no value is provided for this field, visibility is based on the stringified value of `controlling_value_regex`.
*/

/**
* #### Advanced visibility
* @typedef {Object} ADVANCED_VISIBILITY
* @property {'OR'|'AND'} [advanced_visibility.boolean_operator=OR] `OR` The boolean operator for the conditional criteria. Can be `AND` or `OR`
* @property {Array<ADVANCED_VISIBILITY_CRITERIA>} [advanced_visibility.criteria] An array of visibility objects that defines the conditional criteria that needs to be met for the field to display.
*/

/**
* #### Display conditions
* @description Occasionally, you may want to show a field or field group, but only under specfic conditions. Examples might include: `Address fields that correspond to a specific country` or `An image description that is only entered after an image is selected`
* @typedef {Object} DISPLAY_CONDITIONS
* @property {Object} [visibility] Sets the field's display conditions. For example, you can set a field to only display when another checkbox field has been selected
* @property {HIDDEN_SUBFIELDS} [visibility.hidden_subfields] Hide subfields of a field. For example, you can hide the margin from spacing field and show only the padding. Ony works for Theme settings fields.
* @property {?string} [visibility.controlling_field_path] The path of the field that controls the display condition. If the field is not nested inside a field group, use the field's name (i.e. `field_name`). For fields nested in groups, the path should match its grouping structure, separated by a period. For example: `field_group_name.field_name` or `parent_group.child_group.field_name`
* @property {?string} [visibility.controlling_value_regex] The regular expression in the controlling field that needs to be present for the field to display. The regex must match the entire string (not a subset) and is run case-sensitively.
* @property {'NOT_EQUAL'|'EQUAL'|'EMPTY'|'NOT_EMPTY'|'MATCHES_REGEX'} [visibility.operator=EMPTY] `EMPTY` The operator that defines how the `controlling_value_regex` value needs to be met
* @property {?string} [visibility.property] Sets visibility based on a specific property of the target field. For example, you can enable visibility when an image field's src property is equal to a specific value. By default, if no value is provided for this field, visibility is based on the stringified value of `controlling_value_regex`.
* @property {Object} [advanced_visibility] To include multiple criteria with multiple operators, as well as order of operations, you can use advanced_visibility.
* @property {'OR'|'AND'} [advanced_visibility.boolean_operator=OR] `OR` The boolean operator for the conditional criteria. Can be `AND` or `OR`
* @property {Object[]} [advanced_visibility.criteria] An array of visibility objects that defines the conditional criteria that needs to be met for the field to display.
* @property {string} [advanced_visibility.criteria[].controlling_field_path] The path of the field that controls the display condition.
* @property {string} [advanced_visibility.criteria[].controlling_value_regex] The value in the controlling field that needs to be met to display the field.
* @property {'NOT_EQUAL'|'EQUAL'|'EMPTY'|'NOT_EMPTY'|'MATCHES_REGEX'} [advanced_visibility.criteria[].operator] The operator that defines how the `controlling_value_regex` value needs to be met.
* @property {Array<ADVANCED_VISIBILITY_CRITERIA>} [advanced_visibility.criteria] An array of visibility objects that defines the conditional criteria that needs to be met for the field to display.
* @property {Array<ADVANCED_VISIBILITY>} [advanced_visibility.children]
*/

/**
Expand Down Expand Up @@ -55,7 +90,11 @@
* @property {string} [tab]
* @property {boolean} [locked]
* @property {Array<COMMON_FIELDS>} [children]
*/

/**
* #### nested common fields
* @typedef { COMMON_FIELDS | COMMON_FIELDS[] | Array<COMMON_FIELDS | COMMON_FIELDS[]> | Array<COMMON_FIELDS | Array<COMMON_FIELDS | COMMON_FIELDS[]>> } NESTED_COMMON_FIELDS
*/

export default {}
Loading

0 comments on commit 017a6d5

Please sign in to comment.