UNPKG

handsontable

Version:

Handsontable is a JavaScript Data Grid available for React, Angular and Vue.

348 lines (325 loc) • 16.9 kB
"use strict"; exports.__esModule = true; exports.validateColorScheme = validateColorScheme; exports.validateDensityType = validateDensityType; exports.validateParams = validateParams; var _object = require("../../../helpers/object"); var _console = require("../../../helpers/console"); var _errors = require("../../../helpers/errors"); /** * Valid parameters keys. * * @type {Set<string>} */ const VALID_PARAMS_KEYS = new Set(['name', 'sizing', 'density', 'icons', 'colors', 'tokens', 'colorScheme']); /** * Valid color scheme values. * * @type {Set<string>} */ const VALID_COLOR_SCHEMES = new Set(['light', 'dark', 'auto']); /** * Valid density type values. * * @type {Set<string>} */ const VALID_DENSITY_TYPES = new Set(['default', 'compact', 'comfortable']); /** * Valid icon key values. * * @type {Set<string>} */ const VALID_ICON_KEYS = exports.VALID_ICON_KEYS = new Set(['arrowRight', 'arrowRightWithBar', 'arrowLeft', 'arrowLeftWithBar', 'arrowDown', 'menu', 'selectArrow', 'arrowNarrowUp', 'arrowNarrowDown', 'check', 'checkbox', 'caretHiddenLeft', 'caretHiddenRight', 'caretHiddenUp', 'caretHiddenDown', 'collapseOff', 'collapseOn', 'radio', 'chipClose', 'search']); /** * Valid token key values. * * @type {Set<string>} */ const VALID_TOKEN_KEYS = new Set([ // Typography 'fontFamily', 'fontSize', 'fontSizeSmall', 'lineHeight', 'lineHeightSmall', 'fontWeight', 'letterSpacing', // Layout 'gapSize', 'iconSize', 'tableTransition', // Base colors 'borderColor', 'accentColor', 'foregroundColor', 'foregroundSecondaryColor', 'backgroundColor', 'backgroundSecondaryColor', 'placeholderColor', 'readOnlyColor', 'disabledColor', // Shadow 'shadowColor', 'shadowX', 'shadowY', 'shadowBlur', 'shadowOpacity', // Bars 'barForegroundColor', 'barBackgroundColor', 'barHorizontalPadding', 'barVerticalPadding', // Cell 'cellHorizontalBorderColor', 'cellVerticalBorderColor', 'cellHorizontalPadding', 'cellVerticalPadding', // Wrapper 'wrapperBorderWidth', 'wrapperBorderRadius', 'wrapperBorderColor', // Row 'rowHeaderOddBackgroundColor', 'rowHeaderEvenBackgroundColor', 'rowCellOddBackgroundColor', 'rowCellEvenBackgroundColor', // Cell editor 'cellEditorBorderWidth', 'cellEditorBorderColor', 'cellEditorForegroundColor', 'cellEditorBackgroundColor', 'cellEditorShadowBlurRadius', 'cellEditorShadowColor', // Cell states 'cellSuccessBackgroundColor', 'cellErrorBackgroundColor', 'cellReadOnlyBackgroundColor', // Cell selection 'cellSelectionBorderColor', 'cellSelectionBackgroundColor', // Cell autofill 'cellAutofillSize', 'cellAutofillHitAreaSize', 'cellAutofillBorderWidth', 'cellAutofillBorderRadius', 'cellAutofillBorderColor', 'cellAutofillBackgroundColor', 'cellAutofillFillBorderColor', // Cell mobile 'cellMobileHandleSize', 'cellMobileHandleBorderWidth', 'cellMobileHandleBorderRadius', 'cellMobileHandleBorderColor', 'cellMobileHandleBackgroundColor', 'cellMobileHandleBackgroundOpacity', // Resize/Move indicators 'resizeIndicatorColor', 'moveBacklightColor', 'moveBacklightOpacity', 'moveIndicatorColor', 'hiddenIndicatorColor', // Scrollbar 'scrollbarBorderRadius', 'scrollbarTrackColor', 'scrollbarThumbColor', // Header 'headerFontWeight', 'headerForegroundColor', 'headerBackgroundColor', 'headerHighlightedShadowSize', 'headerHighlightedForegroundColor', 'headerHighlightedBackgroundColor', 'headerActiveBorderColor', 'headerActiveForegroundColor', 'headerActiveBackgroundColor', 'headerFilterBackgroundColor', // Header row 'headerRowForegroundColor', 'headerRowBackgroundColor', 'headerRowHighlightedForegroundColor', 'headerRowHighlightedBackgroundColor', 'headerRowActiveForegroundColor', 'headerRowActiveBackgroundColor', // Checkbox 'checkboxSize', 'checkboxBorderRadius', 'checkboxBorderColor', 'checkboxBackgroundColor', 'checkboxIconColor', 'checkboxFocusBorderColor', 'checkboxFocusBackgroundColor', 'checkboxFocusIconColor', 'checkboxFocusRingColor', 'checkboxDisabledBorderColor', 'checkboxDisabledBackgroundColor', 'checkboxDisabledIconColor', 'checkboxCheckedBorderColor', 'checkboxCheckedBackgroundColor', 'checkboxCheckedIconColor', 'checkboxCheckedFocusBorderColor', 'checkboxCheckedFocusBackgroundColor', 'checkboxCheckedFocusIconColor', 'checkboxCheckedDisabledBorderColor', 'checkboxCheckedDisabledBackgroundColor', 'checkboxCheckedDisabledIconColor', 'checkboxIndeterminateBorderColor', 'checkboxIndeterminateBackgroundColor', 'checkboxIndeterminateIconColor', 'checkboxIndeterminateFocusBorderColor', 'checkboxIndeterminateFocusBackgroundColor', 'checkboxIndeterminateFocusIconColor', 'checkboxIndeterminateDisabledBorderColor', 'checkboxIndeterminateDisabledBackgroundColor', 'checkboxIndeterminateDisabledIconColor', // Radio 'radioSize', 'radioBorderColor', 'radioBackgroundColor', 'radioIconColor', 'radioFocusBorderColor', 'radioFocusBackgroundColor', 'radioFocusIconColor', 'radioFocusRingColor', 'radioDisabledBorderColor', 'radioDisabledBackgroundColor', 'radioDisabledIconColor', 'radioCheckedBorderColor', 'radioCheckedBackgroundColor', 'radioCheckedIconColor', 'radioCheckedFocusBorderColor', 'radioCheckedFocusBackgroundColor', 'radioCheckedFocusIconColor', 'radioCheckedDisabledBorderColor', 'radioCheckedDisabledBackgroundColor', 'radioCheckedDisabledIconColor', // Icon button 'iconButtonBorderRadius', 'iconButtonLargeBorderRadius', 'iconButtonLargePadding', 'iconButtonBorderColor', 'iconButtonBackgroundColor', 'iconButtonIconColor', 'iconButtonHoverBorderColor', 'iconButtonHoverBackgroundColor', 'iconButtonHoverIconColor', 'iconButtonActiveBorderColor', 'iconButtonActiveBackgroundColor', 'iconButtonActiveIconColor', 'iconButtonActiveHoverBorderColor', 'iconButtonActiveHoverBackgroundColor', 'iconButtonActiveHoverIconColor', // Collapse button 'collapseButtonBorderRadius', 'collapseButtonOpenBorderColor', 'collapseButtonOpenBackgroundColor', 'collapseButtonOpenIconColor', 'collapseButtonOpenIconActiveColor', 'collapseButtonOpenHoverBorderColor', 'collapseButtonOpenHoverBackgroundColor', 'collapseButtonOpenHoverIconColor', 'collapseButtonOpenHoverIconActiveColor', 'collapseButtonCloseBorderColor', 'collapseButtonCloseBackgroundColor', 'collapseButtonCloseIconColor', 'collapseButtonCloseIconActiveColor', 'collapseButtonCloseHoverBorderColor', 'collapseButtonCloseHoverBackgroundColor', 'collapseButtonCloseHoverIconColor', 'collapseButtonCloseHoverIconActiveColor', // Button 'buttonBorderRadius', 'buttonHorizontalPadding', 'buttonVerticalPadding', // Primary button 'primaryButtonBorderColor', 'primaryButtonForegroundColor', 'primaryButtonBackgroundColor', 'primaryButtonDisabledBorderColor', 'primaryButtonDisabledForegroundColor', 'primaryButtonDisabledBackgroundColor', 'primaryButtonHoverBorderColor', 'primaryButtonHoverForegroundColor', 'primaryButtonHoverBackgroundColor', 'primaryButtonFocusBorderColor', 'primaryButtonFocusForegroundColor', 'primaryButtonFocusBackgroundColor', // Secondary button 'secondaryButtonBorderColor', 'secondaryButtonForegroundColor', 'secondaryButtonBackgroundColor', 'secondaryButtonDisabledBorderColor', 'secondaryButtonDisabledForegroundColor', 'secondaryButtonDisabledBackgroundColor', 'secondaryButtonHoverBorderColor', 'secondaryButtonHoverForegroundColor', 'secondaryButtonHoverBackgroundColor', 'secondaryButtonFocusBorderColor', 'secondaryButtonFocusForegroundColor', 'secondaryButtonFocusBackgroundColor', // Comments 'commentsTextareaHorizontalPadding', 'commentsTextareaVerticalPadding', 'commentsTextareaBorderWidth', 'commentsTextareaBorderColor', 'commentsTextareaForegroundColor', 'commentsTextareaBackgroundColor', 'commentsTextareaFocusBorderWidth', 'commentsTextareaFocusBorderColor', 'commentsTextareaFocusForegroundColor', 'commentsTextareaFocusBackgroundColor', 'commentsIndicatorSize', 'commentsIndicatorColor', // License 'licenseHorizontalPadding', 'licenseVerticalPadding', 'licenseForegroundColor', 'licenseBackgroundColor', // Link 'linkColor', 'linkHoverColor', // Input 'inputBorderWidth', 'inputBorderRadius', 'inputHorizontalPadding', 'inputVerticalPadding', 'inputBorderColor', 'inputForegroundColor', 'inputBackgroundColor', 'inputHoverBorderColor', 'inputHoverForegroundColor', 'inputHoverBackgroundColor', 'inputDisabledBorderColor', 'inputDisabledForegroundColor', 'inputDisabledBackgroundColor', 'inputFocusBorderColor', 'inputFocusForegroundColor', 'inputFocusBackgroundColor', // Menu 'menuBorderWidth', 'menuBorderRadius', 'menuHorizontalPadding', 'menuVerticalPadding', 'menuItemHorizontalPadding', 'menuItemVerticalPadding', 'menuBorderColor', 'menuShadowX', 'menuShadowY', 'menuShadowBlur', 'menuShadowColor', 'menuShadowOpacity', 'menuItemHoverColor', 'menuItemHoverColorOpacity', 'menuItemActiveColor', 'menuItemActiveColorOpacity', // Dialog 'dialogSemiTransparentBackgroundColor', 'dialogSemiTransparentBackgroundOpacity', 'dialogSolidBackgroundColor', 'dialogContentPaddingHorizontal', 'dialogContentPaddingVertical', 'dialogContentBorderRadius', 'dialogContentBackgroundColor', // Pagination 'paginationBarForegroundColor', 'paginationBarBackgroundColor', 'paginationBarHorizontalPadding', 'paginationBarVerticalPadding', // Multiselect 'chipBackground', 'chipBorderRadius', 'chipVerticalPadding', 'chipHorizontalPadding', 'chipGap']); /** * Validates a theme name value. * * @param {string} name The theme name to validate. * @param {string} context The context name for error messages. * @throws {Error} If the name is not a non-empty string. * @returns {string} The validated name. */ function validateName(name, context) { if (typeof name !== 'string' || name.trim() === '') { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.name must be a non-empty string.`); } return name; } /** * Validates a color scheme value. * * @param {string} mode The color scheme to validate. * @throws {Error} If the color scheme is invalid. * @returns {string} The validated color scheme. */ function validateColorScheme(mode) { if (!VALID_COLOR_SCHEMES.has(mode)) { const validModes = [...VALID_COLOR_SCHEMES].join(', '); (0, _errors.throwWithCause)(`[ThemeBuilder] Invalid color scheme: "${mode}". Must be one of: ${validModes}.`); } return mode; } /** * Validates and returns a density type. * * @param {string} type The density type to validate. * @throws {Error} If the density type is invalid. * @returns {string} The validated density type. */ function validateDensityType(type) { if (!VALID_DENSITY_TYPES.has(type)) { const validTypes = [...VALID_DENSITY_TYPES].join(', '); (0, _errors.throwWithCause)(`[ThemeBuilder] Invalid density: "${type}". Must be one of: ${validTypes}.`); } return type; } /** * Validates the structure of the density sizes object. * * @param {object} sizes The density sizes object to validate. * @param {string} context The context name for error messages. * @throws {Error} If the density sizes structure is invalid. */ function validateDensitySizes(sizes, context) { if (!(0, _object.isObject)(sizes)) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.sizes must be an object.`); } Object.keys(sizes).forEach(key => { if (!VALID_DENSITY_TYPES.has(key)) { (0, _console.warn)(`[ThemeBuilder] Unknown density size key: "${key}" in ${context}.sizes. ` + 'This may be a custom density size or a typo.'); } }); } /** * @param {object} density The density object to validate. * @param {string} context The context name for error messages. * @throws {Error} If the density structure is invalid. */ function validateDensityStructure(density, context) { if ((0, _object.isObject)(density)) { if (!density.type || !density.sizes) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context} must be a string or an object with a 'type' and 'sizes' property.`); } validateDensityType(density.type); validateDensitySizes(density.sizes, `${context}.sizes`); } else if (typeof density === 'string') { validateDensityType(density); } } /** * Validates the structure of the colors object. * Colors can be either strings or nested objects containing strings. * * @param {object} colors The colors object to validate. * @param {string} context The context path for error messages. * @throws {Error} If the colors structure is invalid. */ function validateColorsStructure(colors, context) { Object.entries(colors).forEach(_ref => { let [key, value] = _ref; const currentPath = `${context}.${key}`; if (typeof value === 'string') { return; } if ((0, _object.isObject)(value)) { validateColorsStructure(value, currentPath); } else { (0, _errors.throwWithCause)(`[ThemeBuilder] ${currentPath} must be a string or an object.`); } }); } /** * Validates keys and warns about unknown or missing keys. * * @param {object} obj The object to validate. * @param {Set<string>} validKeys The set of valid keys. * @param {string} context The context name for warning messages. * @param {object} [options] Validation options. * @param {string} [options.type='key'] The type name for warning messages. * @param {boolean} [options.warnMissing=false] Whether to warn about missing keys. */ function validateKeys(obj, validKeys, context) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; const { type = 'key', warnMissing = false } = options; if (!obj) { if (warnMissing) { (0, _console.warn)(`[ThemeBuilder] No ${type}s provided in ${context}. All ${type}s are missing.`); } return; } const providedKeys = Object.keys(obj); // Warn about unknown keys providedKeys.forEach(key => { if (!validKeys.has(key)) { (0, _console.warn)(`[ThemeBuilder] Unknown ${type} key: "${key}" in ${context}. ` + `This may be a custom ${type} or a typo.`); } }); // Warn about missing keys only if required if (warnMissing) { const missingKeys = []; validKeys.forEach(key => { if (!(key in obj)) { missingKeys.push(key); } }); if (missingKeys.length > 0) { (0, _console.warn)(`[ThemeBuilder] Missing ${type}(s) in ${context}: ${missingKeys.join(', ')}`); } } } /** * Validates the parameters object structure. * * @param {*} parameters The parameters object to validate. * @param {string} context The context name for error messages. * @param {object} [options] Validation options. * @param {string[]} [options.requiredFields=[]] Array of field names that are required. * @throws {Error} If the parameters object structure is invalid. */ function validateParams(parameters, context) { let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; const { requiredFields = [] } = options; if (typeof parameters !== 'object' || parameters === null) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context} must be an object.`); } const { name, sizing, density, icons, colors, tokens, colorScheme } = parameters; validateKeys(parameters, VALID_PARAMS_KEYS, context, { type: 'param' }); // Validate required fields requiredFields.forEach(field => { if (parameters[field] === undefined) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.${field} is required.`); } }); // Validate name if (name !== undefined) { validateName(name, context); } // Validate sizing if (sizing !== undefined) { if (!(0, _object.isObject)(sizing)) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.sizing must be an object.`); } } // Validate density if (density !== undefined) { if (!(0, _object.isObject)(density) && typeof density !== 'string') { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.density must be a string or an object.`); } validateDensityStructure(density, `${context}.density`); } // Validate icons if (icons !== undefined) { if (!(0, _object.isObject)(icons)) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.icons must be an object.`); } validateKeys(icons, VALID_ICON_KEYS, `${context}.icons`, { type: 'icon', warnMissing: requiredFields.includes('icons') }); } // Validate colors if (colors !== undefined) { if (!(0, _object.isObject)(colors)) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.colors must be an object.`); } validateColorsStructure(colors, `${context}.colors`); } // Validate tokens if (tokens !== undefined) { if (!(0, _object.isObject)(tokens)) { (0, _errors.throwWithCause)(`[ThemeBuilder] ${context}.tokens must be an object.`); } validateKeys(tokens, VALID_TOKEN_KEYS, `${context}.tokens`, { type: 'token', warnMissing: requiredFields.includes('tokens') }); } // Validate color scheme if (colorScheme !== undefined) { validateColorScheme(colorScheme); } }