/** * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core) * Author: Steve Slevinski (https://SteveSlevinski.me) * style.cjs is released under the MIT License. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /** * Object of regular expressions for style strings * * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full } * @alias style.re * @type {object} */ let re = { 'colorize': 'C', 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}', 'colorname': '[a-zA-Z]+', 'padding': 'P[0-9]{2}', 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)', 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?', 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}', 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}' }; re.colorbase = `(?:${re.colorhex}|${re.colorname})`; re.color = `_${re.colorbase}_`; re.colors = `_${re.colorbase}(?:,${re.colorbase})?_`; re.background = `G${re.color}`; re.detail = `D${re.colors}`; re.detailsym = `D[0-9]{2}${re.colors}`; re.classes = `${re.classbase}(?: ${re.classbase})*`; re.full = `-(${re.colorize})?(${re.padding})?(${re.background})?(${re.detail})?(${re.zoom})?(?:-((?:${re.detailsym})*)((?:${re.zoomsym})*))?(?:-(${re.classes})?!(?:(${re.id})!)?)?`; const prefixColor = color => { const regex = new RegExp(`^${re.colorhex}$`); return (regex.test(color) ? '#' : '') + color; }; /** * Function to parse style string to object * @function style.parse * @param {string} styleString - a style string * @returns {object} elements of style string * @example * style.parse('-CP10G_blue_D_red,Cyan_') * * return { * 'colorize': true, * 'padding': 10, * 'background': 'blue', * 'detail': ['red', 'Cyan'] * } */ const parse = styleString => { const regex = `^${re.full}`; const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || []; return { 'colorize': !m[1] ? undefined : !!m[1], 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)), 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)), 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor), 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)), 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re.detailsym, 'g')).map(val => { const parts = val.split('_'); const detail = parts[1].split(',').map(prefixColor); return { 'index': parseInt(parts[0].slice(1)), 'detail': detail }; }), 'zoomsym': !m[7] ? undefined : m[7].match(new RegExp(re.zoomsym, 'g')).map(val => { const parts = val.split(','); return { 'index': parseInt(parts[0].slice(1)), 'zoom': parseFloat(parts[1]), 'offset': !parts[2] ? undefined : parts[2].split('x').map(val => parseInt(val) - 500) }; }), 'classes': !m[8] ? undefined : m[8], 'id': !m[9] ? undefined : m[9] }; }; /** * Function to compose style string from object * @function style.compose * @param {object} styleObject - an object of style options * @param {boolean} styleObject.colorize - boolean to use standardized colors for symbol groups * @param {number} styleObject.padding - integer value for padding around symbol or sign * @param {string} styleObject.background - css name or hex color for background * @param {string[]} styleObject.detail - css name or hex color for line and optional fill * @param {number} styleObject.zoom - decimal value for zoom level * @param {{index:number,detail:string[]}[]} styleObject.detailsym - array of symbol indexes and detail color array * @param {{index:number,zoom:number,offset:number[]}[]} styleObject.zoomsym - array of symbol indexes and zoom levels with optional x,y offset * @param {string} styleObject.classes - list of class names separated with spaces used for SVG * @param {string} styleObject.id - id name used for SVG * @returns {string} style string * @example * style.compose({ * 'colorize': true, * 'padding': 10, * 'background': 'blue', * 'detail': ['red', 'Cyan'], * 'zoom': 1.1, * 'detailsym': [ * { * 'index': 1, * 'detail': ['#ff00ff'] * }, * { * 'index': 2, * 'detail': ['yellow', 'green'] * } * ], * 'zoomsym': [ * { * 'index': 1, * 'zoom': 10, * 'offset': [0, 0] * }, * { * 'index': 2, * 'zoom': 5.5 * } * ], * 'classes': 'primary blinking', * 'id': 'cursor' * }) * * return '-CP10G_blue_D_red,Cyan_Z1.1-D01_ff00ff_D02_yellow,green_Z01,10,500x500Z02,5.5-primary blinking!cursor!' */ const compose = styleObject => { if (typeof styleObject !== 'object' || styleObject === null) return undefined; // three sections let style1 = '-'; style1 += !styleObject.colorize ? '' : 'C'; const padding = parseInt(styleObject.padding); style1 += !padding || padding <= 0 || padding > 99 ? '' : 'P' + (padding > 9 ? padding : '0' + padding); const background = !styleObject.background || !(typeof styleObject.background === 'string') ? undefined : styleObject.background.match(re.colorbase)[0]; style1 += !background ? '' : 'G_' + background + '_'; const detail1 = !styleObject.detail || !styleObject.detail[0] || !(typeof styleObject.detail[0] === 'string') ? undefined : styleObject.detail[0].match(re.colorbase)[0]; const detail2 = !styleObject.detail || !styleObject.detail[1] || !(typeof styleObject.detail[1] === 'string') ? undefined : styleObject.detail[1].match(re.colorbase)[0]; if (detail1) { style1 += 'D_' + detail1; if (detail2) { style1 += ',' + detail2; } style1 += '_'; } const zoom = styleObject.zoom === 'x' ? 'x' : parseFloat(styleObject.zoom); style1 += !zoom || zoom <= 0 ? '' : 'Z' + zoom; let style2 = ''; const detailsym = !styleObject.detailsym || !Array.isArray(styleObject.detailsym) ? [] : styleObject.detailsym.map(styleObject => { const index = parseInt(styleObject.index); if (!index || index <= 0 || index > 99) return ''; let style = 'D' + (index > 9 ? index : '0' + index); const detail1 = !styleObject.detail || !styleObject.detail[0] ? undefined : styleObject.detail[0].match(re.colorbase)[0]; const detail2 = !styleObject.detail || !styleObject.detail[1] ? undefined : styleObject.detail[1].match(re.colorbase)[0]; if (detail1) { style += '_' + detail1; if (detail2) { style += ',' + detail2; } style += '_'; } return style; }); style2 += detailsym.join(''); const zoomsym = !styleObject.zoomsym || !Array.isArray(styleObject.zoomsym) ? [] : styleObject.zoomsym.map(styleObject => { const index = parseInt(styleObject.index); if (!index || index <= 0 || index > 99) return ''; let style = 'Z' + (index > 9 ? index : '0' + index); const zoom = parseFloat(styleObject.zoom); style += !zoom || zoom <= 0 ? '' : ',' + zoom; if (styleObject.offset && 0 in styleObject.offset && 1 in styleObject.offset) { const x = parseInt(styleObject.offset[0]) + 500; const y = parseInt(styleObject.offset[1]) + 500; if (x >= 250 && x < 750 && y >= 250 && y < 750) { style += ',' + x + 'x' + y; } } return style; }); style2 += zoomsym.join(''); let style3 = ''; const classes = !styleObject.classes || !(typeof styleObject.classes === 'string') ? undefined : styleObject.classes.match(re.classes)[0]; style3 += !classes ? '' : classes; const id = !styleObject.id || !(typeof styleObject.id === 'string') ? undefined : styleObject.id.match(re.id)[0]; style3 += classes || id ? '!' : ''; style3 += !id ? '' : id + '!'; return style1 + (style2 || style3 ? '-' + style2 : '') + (style3 ? '-' + style3 : ''); }; exports.compose = compose; exports.parse = parse; exports.re = re; /* support ongoing development on https://patreon.com/signwriting */