diff --git a/helpers.js b/helpers.js index ec2a05d..a2301d6 100644 --- a/helpers.js +++ b/helpers.js @@ -14,6 +14,7 @@ import {constants} from "fs"; import fetch from "node-fetch"; import mime from "mime-types"; import {exec} from "child_process"; +import {REGISTRY_URL} from "@axe-web/create-block/env.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -61,14 +62,16 @@ export async function getBlockData(jsonFileName = 'default', {projectPath} = {js return data; } -export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) { - const updatedConfig = Object.assign(JSON.parse(JSON.stringify(config)), // The entire config object. +export async function getBlockConfigs(args) { + const config = await readJSONFile(path.join('blocks', '@' + args.project, args.name, 'config', 'default.json')); + + const updatedConfig = Object.assign({}, config, // The entire config object. { - projectDir: args.modulesPath, dataFiles: args.dataFiles.map((name) => { + projectDir: '', dataFiles: args.dataFiles.map((name) => { return { name, }; - }), remToPx: config.has('remToPx') ? config.get('remToPx') : 16, + }), remToPx: 16, }); // Avoid cache conflict on Global Project css/js files. @@ -81,13 +84,13 @@ export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) { } export function getBlockName(name = '') { - if (name.startsWith('@')) { - name = name.substring(1); - } + // Remove all @ from the beginning of the string. + name = name.replace(/^@/, ''); const arr = name.split('/'); return { + blockName: `@${arr[0]}/${arr[1]}`, project: arr[0], name: arr[1], }; @@ -275,7 +278,7 @@ export async function getBlockFromCloud(blockName, blocksRegistry) { const response = await fetch(`${blocksRegistry}?${queryString.toString()}`); const responseData = await response.json(); if (!responseData || !responseData.name) { - const message = "⚠️ Block not found, please contact administrator." + const message = `⚠️ Block not found, please contact administrator. [${blockName}]` throw new Error(message); } @@ -287,12 +290,15 @@ export async function getBlockFromCloud(blockName, blocksRegistry) { return responseData; } -export async function verifyVersion(projectPath, blocksRegistry) { - const blockJson = await readJSONFile(path.join(projectPath, `block.json`)); - const blockName = getBlockName(blockJson.name); +export async function verifyVersion(blockName, projectPath, blocksRegistry) { + const block = await getBlockFromCloud(blockName, blocksRegistry); + if (!block) { + throw new Error(`Block not found. [${blockName}]`); + } - if (typeof blockJson.version === 'undefined' || !blockName.name) { - return true; + const blockJson = await readJSONFile(path.join(projectPath, `block.json`)); + if (blockJson.error) { + return false; // Block doesn't exist locally. } /* @@ -300,25 +306,28 @@ export async function verifyVersion(projectPath, blocksRegistry) { * Let's detect the latest version. */ - const block = await getBlockFromCloud('@' + blockJson.name, blocksRegistry); return block.version === blockJson.version; } -export async function syncFilesWithCloud(jsonBlockPath, bs, sourceFiles = false) { - const blockJson = await readJSONFile(jsonBlockPath); - const blockName = blockJson.name.startsWith('@') ? blockJson.name : `@${blockJson.name}`; +export async function syncFilesWithCloud(blockName, bs, sourceFiles = false) { + const block = await getBlockFromCloud(blockName, REGISTRY_URL); - bs.pause(); + let fileExists = false; + try { + await readJSONFile(path.join('blocks', '@' + block.project, block.name, 'block.json')); + fileExists = true; + } catch (e) { + // Dir doesn't exist. + } - // Looks like it takes time to pause the browser-sync server, so delay(setTimeout) is necessary. - await new Promise((resolve) => setTimeout(() => resolve(), 1000)); + // TODO: Pause watcher of the block? + blockName = `@${block.project}/${block.name}`; await new Promise((resolve) => { - const args = sourceFiles ? '--source' : ''; const createBlockModulePath = `./node_modules/@axe-web/create-block`; + const action = sourceFiles ? fileExists ? 'sync --source' : 'pull' : 'sync'; - // exec(`BLOCK_NAME=${blockName} node ${createBlockModulePath}/create-block.js sync ${args}`, (err, stdout, stderr) => { - exec(`node ${createBlockModulePath}/create-block.js sync ${args}`, (err, stdout, stderr) => { + exec(`BLOCK_NAME=${blockName} node ${createBlockModulePath}/create-block.js ${action}`, (err, stdout, stderr) => { if (err || stderr) { const message = err || stderr; console.error('Error:', message); @@ -330,5 +339,54 @@ export async function syncFilesWithCloud(jsonBlockPath, bs, sourceFiles = false) }); }); - bs.resume(); + // TODO: Release watcher of the block? +} + +export async function getBlockVariations(projectPath) { + const dataFiles = []; + + try { + await fs.access(path.join(projectPath, 'data')); + + const files = prepareListOfDataFiles(await fs.readdir(path.join(projectPath, 'data'))); + dataFiles.push(...files); + } catch (e) { + console.log('Warning: data folder not found.', projectPath); + } + + return dataFiles; +} + +export function prepareListOfDataFiles(dataFiles) { + return dataFiles + .filter((fileName) => fileName.split('.').pop() === 'json') + .map((fileName) => { + const splitName = fileName.split('.'); + splitName.pop(); + return splitName.join(''); + }) + .sort(); +} + +export function handlebarLayoutsPath() { + return path.join(...arguments) + .replace(/\\/g, '/'); // Windows path issue. Fix all "\" for Handlebars. +} + +export function getListOfDesignPreviewFiles(jsonDataFileName, previewFiles, block) { + return previewFiles + .filter(fileName => { + return fileName.startsWith(jsonDataFileName + '.'); + }) + .map(fileName => { + const fileData = fileName.split('.'); + const fileFormat = fileData.pop(); + const previewSize = fileData.pop(); + + return { + dataSource: jsonDataFileName, + widthDimension: Number.parseInt(previewSize, 10), + url: `/design/${block.project}/${block.name}/preview/${fileName}`, + }; + }); } diff --git a/inc/changes-watcher.js b/inc/changes-watcher.js new file mode 100644 index 0000000..f87bc17 --- /dev/null +++ b/inc/changes-watcher.js @@ -0,0 +1,109 @@ +import gulp from "gulp"; +import path from "path"; +import sourcemaps from "gulp-sourcemaps"; +import babel from "gulp-babel"; +import PluginError from "plugin-error"; +import rename from "gulp-rename"; +import uglify from "gulp-uglify"; +import dartSass from 'sass'; +import gulpSass from "gulp-sass"; +import {getBlockName} from "../helpers.js"; + +const sass = gulpSass(dartSass); + +export function setupWatcher(viewSync) { + + const watchSCSS = gulp.watch(['blocks/**/*.scss'], {delay: 400}); + watchSCSS.on('change', async function (filepath, stats) { + const pathArray = filepath.split('/', 3); + pathArray.shift(); + const block = getBlockName(pathArray.join('/')); + + buildStyleFiles(path.join('blocks', '@' + block.project, block.name), () => { + viewSync.syncTemplate(block.blockName, 'styleUpdate'); + }) + }); + + const watchJS = gulp.watch(['blocks/**/*.js', '!blocks/**/*.min.js'], {delay: 400}); + watchJS.on('change', async function (filepath) { + const pathArray = filepath.split('/', 3); + pathArray.shift(); + const block = getBlockName(pathArray.join('/')); + + buildScriptFiles(path.join('blocks', '@' + block.project, block.name), () => { + viewSync.syncTemplate(block.blockName, 'scriptUpdate'); + }) + }); + + const watchHBS = gulp.watch(['blocks/**/*.hbs'], {delay: 400}); + watchHBS.on('change', async function (filepath) { + const pathArray = filepath.split('/', 3); + pathArray.shift(); + const block = getBlockName(pathArray.join('/')); + + await viewSync.syncTemplate(block.blockName); + }); + +} + +export function buildAssetFiles(projectPath) { + // Register tasks. + gulp.task('build-script-files', (done) => buildScriptFiles(projectPath, done)); + gulp.task('build-styling-files', (done) => buildStyleFiles(projectPath, done)); + + // Run first build. + return new Promise((resolve) => { + gulp.series('build-script-files', 'build-styling-files', function () { + resolve(); + })(); + }); +} + +function showError(errorMessage) { + console.log(errorMessage); + + // TODO: Send this message to browser. + // So the developer can understand there is an error. +} + +function buildScriptFiles(projectPath = '', done) { + const files = getJSBundleFiles(projectPath); + const stream = gulp.src(files, {base: path.posix.join(projectPath, 'src')}) + .pipe(sourcemaps.init({})) + .pipe(babel()).on('error', function (error) { + showError(new PluginError('JavaScript', error).toString()); + done(); + }) + .pipe(gulp.src(path.join(projectPath, 'vendor/*.js'))) + // .pipe(gulp.dest('src/')) + .pipe(rename({extname: '.min.js'})) + .pipe(uglify()) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest(path.posix.join(projectPath, 'src'))); + + stream.on('end', done); + + return stream; +} + +function getJSBundleFiles(projectPath = '') { + return [path.posix.join(projectPath, "src/**/*.js"), path.posix.join(projectPath, "src/**/*.mjs"), "!" + path.posix.join(projectPath, "src/**/*.min.js")]; +} + +function buildStyleFiles(projectPath = '', done) { + const stream = gulp.src(path.join(projectPath, 'src/**/*.scss'), {base: path.posix.join(projectPath, 'src')}) + .pipe(sourcemaps.init({})) + .pipe(sass.sync({outputStyle: 'compressed'}).on('error', function (error) { + showError(new PluginError('SCSS', error.messageFormatted).toString()); + // sass.logError(error); + done(); + })) + // .pipe(gulp.dest('src/')) + .pipe(rename({extname: '.min.css'})) + .pipe(sourcemaps.write('.', {})) + .pipe(gulp.dest(path.posix.join(projectPath, 'src'))); + + stream.on('end', done); + + return stream; +} diff --git a/inc/server.js b/inc/server.js new file mode 100644 index 0000000..ec18b36 --- /dev/null +++ b/inc/server.js @@ -0,0 +1,53 @@ +import express from "express"; +import bodyParser from "body-parser"; +import {createServer} from "http"; +import {create} from "express-handlebars"; +import {escape} from "lodash-es"; +import {sanitizeUrl} from "@braintree/sanitize-url"; +import path from "path"; + +export function init() { + const app = express(); + + // parse application/x-www-form-urlencoded + app.use(bodyParser.urlencoded({extended: false})); + + // parse application/json + app.use(bodyParser.json()); + + const hbs = getHandlebarsViewEngine(); + + app.engine('.hbs', hbs.engine); + app.set('view engine', '.hbs'); + + const modulesPath = '.'; + app.set('views', path.join(modulesPath, 'layouts')); + + // Static Files of blockDevTool. + app.use(express.static(path.join(modulesPath, 'layouts'))); + + return { + expressApp: app, + httpServer: createServer(app), + }; +} + +function getHandlebarsViewEngine() { + return create({ + extname: '.hbs', defaultLayout: false, partialsDir: ['.'], helpers: handlebarsHelpers() + }); +} + +function handlebarsHelpers() { + return { + esc_attr(attr) { + return escape(attr); + }, + esc_url(url) { + return sanitizeUrl(url); + }, + esc_html(html) { + return html; + }, + }; +} diff --git a/inc/view-sync.js b/inc/view-sync.js new file mode 100644 index 0000000..18b0bce --- /dev/null +++ b/inc/view-sync.js @@ -0,0 +1,50 @@ +import {Server} from "socket.io"; +import fs from "fs/promises"; +import {getBlockName, handlebarLayoutsPath} from "../helpers.js"; +import path from "path"; + +export class ViewSync { + constructor(httpServer) { + this.sessions = {}; + this.init(httpServer); + } + + addSession(session, blockName) { + if (!this.sessions[blockName]) { + this.sessions[blockName] = []; + } + + this.sessions[blockName].push(session); + } + + init(httpServer) { + const io = new Server(httpServer); + io.on('connection', async (socket) => { + const blockName = socket.handshake.query.block; + + if (!blockName) { + return; + } + + this.addSession(socket, blockName); + await this.syncTemplate(blockName); + }); + + // return httpServer; + } + + async syncTemplate(blockName, updateType = 'templateUpdate') { + const block = getBlockName(blockName); + + const projectPath = path.join('blocks', '@' + block.project, block.name); + const hbsTemplate = await fs.readFile(handlebarLayoutsPath(projectPath, 'src', `${block.name}.template.hbs`), 'utf8'); + + if (!this.sessions[blockName]) { + return; + } + + this.sessions[blockName].forEach(session => { + session.emit(updateType, {block: blockName, template: hbsTemplate}); + }); + } +} diff --git a/layouts/index.hbs b/layouts/index.hbs index 99ec74d..58984c9 100644 --- a/layouts/index.hbs +++ b/layouts/index.hbs @@ -7,12 +7,13 @@ Block Development Tool - + {{> (include_partial "layouts/partials/toolbar") }}
- +
diff --git a/layouts/partials/head.hbs b/layouts/partials/head.hbs index 7a1c7bf..87c50d8 100644 --- a/layouts/partials/head.hbs +++ b/layouts/partials/head.hbs @@ -10,5 +10,5 @@ {{/each}} {{/if}}{{# if config.blockName}} - {{/if}} + {{/if}} diff --git a/layouts/partials/scripts.hbs b/layouts/partials/scripts.hbs index eece0f5..ed02e81 100644 --- a/layouts/partials/scripts.hbs +++ b/layouts/partials/scripts.hbs @@ -10,5 +10,5 @@ {{/each}} {{/if}} {{#if config.blockName }} - + {{/if}} diff --git a/layouts/partials/toolbar.hbs b/layouts/partials/toolbar.hbs index 70b018c..a41daa2 100644 --- a/layouts/partials/toolbar.hbs +++ b/layouts/partials/toolbar.hbs @@ -15,6 +15,6 @@ {{#if styleGuideUrl}} {{/if}} - + diff --git a/layouts/scripts/dist/frame-index.min.js b/layouts/scripts/dist/frame-index.min.js index 1514557..9d6e2ed 100644 --- a/layouts/scripts/dist/frame-index.min.js +++ b/layouts/scripts/dist/frame-index.min.js @@ -1 +1 @@ -let e;window.initBlock=function(e="",n="",r){t=function(){document.querySelectorAll(n).forEach((e=>r(e)))},t()};let t,n={};function r(r={}){r.template&&(e=r.template),r.data&&(n=r.data),e&&function(e,n,r){const a=Handlebars.compile(e);let o;Handlebars.registerHelper("esc_attr",(function(e){return e})),Handlebars.registerHelper("esc_url",(function(e){return e})),Handlebars.registerHelper("esc_html",(function(e){return e})),Handlebars.registerHelper("base_url",(function(){return"/"}));try{o=a(n)}catch(e){o=`
\n

Syntax Error:

\n
${e.toString()}
\n
`}r.innerHTML=o,t&&t()}(e,n||{},document.getElementById("hbs-container"))}!function(){function e(){const e=new URLSearchParams(window.location.search),t={};for(const[n,r]of e)t[n]=r;return t}!function(){const t=new URLSearchParams({name:e().data||"default"});fetch(`/data?${t}`).then((e=>e.json())).then((e=>{n=e.data,r({data:n})}))}(),window.addEventListener("message",(function(e){const t=e.data,a="dataUpdate:";if("string"==typeof t&&t.startsWith(a))try{n=JSON.parse(t.substring(a.length)),r({data:n})}catch(e){console.log("Error parsing incoming data.",e)}}))}(),function(){const e=window.io.connect();e.on("error",(function(e){console.log(e)})),e.on("templateUpdate",(function(e){r({template:e.template})}))}(); +let e;window.initBlock=function(e="",n="",o){t=function(){document.querySelectorAll(n).forEach((e=>o(e)))},t()};let t,n={};!function(){const o=r().block;function r(){const e=new URLSearchParams(window.location.search),t={};for(const[n,o]of e)t[n]=o;return t}function a(e){const t=document.getElementById(e),n=t.parentNode;let o,r;return"SCRIPT"===t.tagName?(o=document.createElement("script"),o.type="text/javascript",r="src"):"LINK"===t.tagName&&(o=document.createElement("link"),o.rel="stylesheet",r="href"),o.id=e,o[r]=t[r].replace(/(\?v=)[^&]+/,`$1${Date.now()}`),t.remove(),n.append(o),o}function c(r={}){r.template&&(e=r.template),r.data&&(n=r.data),e&&function(e,n,r){const a=Handlebars.compile(e);let c;Handlebars.registerHelper("esc_attr",(function(e){return e})),Handlebars.registerHelper("esc_url",(function(e){return e})),Handlebars.registerHelper("esc_html",(function(e){return e})),Handlebars.registerHelper("base_url",(function(){const e=["block"];return o&&e.push(o.substr(1)),["",...e,""].join("/")}));try{c=a(n)}catch(e){c=`
\n

Syntax Error:

\n
${e.toString()}
\n
`}r.innerHTML=c,t&&t()}(e,n||{},document.getElementById("hbs-container"))}!function(){const e=new URLSearchParams({block:o,name:r().data||"default"});fetch(`/data?${e}`).then((e=>e.json())).then((e=>{n=e.data,c({data:n})}))}(),window.addEventListener("message",(function(e){const t=e.data,o="dataUpdate:";if("string"==typeof t&&t.startsWith(o))try{n=JSON.parse(t.substring(o.length)),c({data:n})}catch(e){console.log("Error parsing incoming data.",e)}})),function(){const e=window.io.connect("",{query:`block=${o}`});e.on("error",(function(e){console.log(e)})),e.on("templateUpdate",(function(e){c({template:e.template})})),e.on("scriptUpdate",(function(e){a("block-script").onload=()=>{c({template:e.template})}})),e.on("styleUpdate",(function(e){a("block-stylesheet")}))}()}(); diff --git a/layouts/scripts/dist/index.min.js b/layouts/scripts/dist/index.min.js index 98f64fa..db48e12 100644 --- a/layouts/scripts/dist/index.min.js +++ b/layouts/scripts/dist/index.min.js @@ -261,4 +261,4 @@ var U=t.exports,B=$.exports;function V(e){for(var t="https://reactjs.org/docs/er background-repeat: no-repeat; background-position: top; cursor: move; -`;let zp={x:0,y:0};function Np({previewOption:e={widthDimension:0}}){const n=t.exports.createRef(),[r,a]=t.exports.useState(!1),[l,o]=t.exports.useState({x:m(e),y:0}),[i,u]=t.exports.useState(85),s=t.exports.useCallback((function(e){if(!r)return;const t=e.shiftKey?10:1;"ArrowUp"===e.key?p({y:-1*t},!0):"ArrowDown"===e.key?p({y:t},!0):"ArrowLeft"===e.key?p({x:-1*t},!0):"ArrowRight"===e.key&&p({x:t},!0)}),[l,r]);if(t.exports.useEffect((()=>(document.addEventListener("keydown",s),()=>{document.removeEventListener("keydown",s)})),[s]),t.exports.useEffect((()=>(p({x:m(e),y:0}),window.addEventListener("message",h),()=>window.removeEventListener("message",h))),[e.widthDimension]),!e)return;const c=!e.url,f=[];!c&&r&&f.push("active"),c&&f.push("disabled");return M.createElement(M.Fragment,null,M.createElement(_p,{onClick:()=>{a(!r)},className:f.join(" "),disabled:c}),r&&!c&&M.createElement(M.Fragment,null,M.createElement("input",{type:"range",value:i,min:"0",max:"100",onChange:e=>{u(e.target.value)}}),M.createElement(Pp,{onMouseUp:e=>function(e){const t=n.current;p({x:t.offsetLeft,y:t.offsetTop}),document.body.removeEventListener("mousemove",d)}(),style:{opacity:i/100}},M.createElement("img",{src:e.url,alt:"",ref:n,onMouseDown:e=>function(e){zp.x=e.clientX,zp.y=e.clientY,document.body.addEventListener("mousemove",d)}(e),draggable:!1,style:{top:l.y+"px",left:l.x+"px"}}))));function d(e){const t=n.current;if(t){const n={x:t.offsetLeft-(zp.x-e.clientX),y:t.offsetTop-(zp.y-e.clientY)};t.style.left=n.x+"px",t.style.top=n.y+"px",zp.x=e.clientX,zp.y=e.clientY}}function p({x:e,y:t},n=!1){e=void 0===e?l.x:n?l.x+e:e,t=void 0===t?l.y:n?l.y+t:t,o({x:e,y:t})}function m(e){if(!e)return 0;return window.innerWidth/2-e.widthDimension/2-7}function h(t){"responsiveUpdate"===t.data&&"100%"===window.responsiveState.breakpoint&&p({x:m(e),y:0})}}function Tp(e={}){e.rootAttributes=e.rootAttributes??{};const[n,r]=t.exports.useState({dataName:"default",data:{},dataText:"{}",dataOptions:[],designPreview:[],errorMessage:null,loading:!1}),[a,l]=t.exports.useState(f(n.dataName,n.designPreview)),o=e=>r(Object.assign({},n,e)),[i,u]=t.exports.useState(!1);t.exports.useEffect((async()=>{await p(n.dataName)}),[]);const s=t.exports.useCallback((e=>{vp(e)&&c()}),[]);t.exports.useEffect((()=>(document.addEventListener("keydown",s),()=>{document.removeEventListener("keydown",s)})),[s]),t.exports.useEffect((()=>(window.addEventListener("message",d),()=>window.removeEventListener("message",d))),[n]),t.exports.useEffect((()=>{l(f(n.dataName,n.designPreview))}),[n.designPreview]);return M.createElement("div",{style:{display:"flex",gap:"1rem",alignItems:"center"}},M.createElement(xp,{onClick:()=>(u(!0),void setTimeout((()=>document.querySelector(".sidebar-active").focus()))),title:"Open a Sidebar with Data Options"}),M.createElement(Np,{previewOption:a}),M.createElement(wp,{className:i?"active sidebar-active":"",tabIndex:"0",onBlur:async e=>await gp(e)?c():null},M.createElement(Sp,null,M.createElement(Cp,{onClick:()=>c()})),n.dataOptions&&!!n.dataOptions.length&&M.createElement(Ep,null,M.createElement("label",{htmlFor:"data-options"},"Data Options"),M.createElement("select",{name:"data",id:"data-options",onChange:e=>async function(e){const t=e.target.value;await p(t)}(e),value:n.dataName,disabled:n.loading},n.dataOptions.map((e=>{const t=n.dataName===e;return M.createElement("option",{value:e,selected:t},e)})))),n.data&&M.createElement("textarea",{value:n.dataText,onChange:function(e){let t;try{t=JSON.parse(e.target.value)}catch(t){return void o({dataText:e.target.value,errorMessage:"Invalid JSON, please review and try again."})}o({dataText:e.target.value,data:t,errorMessage:null}),m(t)},disabled:n.loading}),n.errorMessage&&M.createElement("p",{className:"alert alert--error"},n.errorMessage),n.loading&&M.createElement("p",{className:"alert"},"Loading, please wait..."),M.createElement("div",{className:"actions"},M.createElement("button",{className:"btn btn--secondary",disabled:n.loading,onClick:e=>function(e,t){e.stopPropagation(),"string"!=typeof t&&(t=JSON.stringify(t,null,2));if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(t);{let n=document.createElement("textarea");return n.value=t,n.style.position="fixed",n.style.left="-999999px",n.style.top="-999999px",document.body.appendChild(n),n.select(),new Promise(((t,r)=>{document.execCommand("copy")?t():r(),n.remove(),e.target.focus()}))}}(e,n.data)},"Copy to Clipboard"),M.createElement("button",{className:"btn btn--secondary",disabled:n.loading,onClick:e=>function(){const e="https://blocks-registery.axe-web.com/content-generator/",t=new Headers;t.append("Content-Type","application/json");const r={method:"POST",headers:t,body:JSON.stringify({json:n.data})};return o({loading:!0,errorMessage:null}),fetch(e,r).then((e=>e.json())).then((e=>{if(console.log(e),200!==e.statusCode)throw new Error(e.message);const t=e.variation;o({dataText:JSON.stringify(t,null,2),data:t,errorMessage:null,loading:!1}),m(t)})).catch((e=>{o({loading:!1,errorMessage:"Something went wrong, please try again."})}))}(n.data)},"Generate Test"))));function c(){u(!1)}function f(e,t=[]){const n=t.filter((t=>t.dataSource===e));n.sort(((e,t)=>t.widthDimension-e.widthDimension));let r=window.responsiveState.breakpoint;return"100%"===r&&(r=window.innerWidth),n.find((e=>r>=e.widthDimension))}function d(e){"responsiveUpdate"===e.data&&l(f(n.dataName,n.designPreview))}async function p(e){const t=await async function(e="default"){const t=new URLSearchParams({name:e}),n=await fetch(`/data?${t}`);return await n.json()}(e);m(t.data);const n=Object.assign({errorMessage:null},t,{dataName:e},{dataText:JSON.stringify(t.data,null,2)});o(n)}function m(t){e.rootAttributes.previewFrame.contentWindow.postMessage("dataUpdate:"+JSON.stringify(t||{}),"*")}}const Lp={previewFrame:document.getElementById("preview_frame")};!function(e){const t=document.createElement("div");document.querySelector(".page_toolbar__middle").prepend(t);const n=jc(t),r=M.createElement(bp,{rootAttributes:e});n.render(r)}(Lp),function(e){const t=document.createElement("div");document.querySelector(".page_toolbar__left").prepend(t);const n=jc(t),r=M.createElement(Tp,{rootAttributes:e});n.render(r)}(Lp),function(e){const t=document.createElement("div");document.querySelector(".page_toolbar__right").append(t);const n=jc(t),r=M.createElement(kp,{rootAttributes:e});n.render(r)}(Lp); +`;let zp={x:0,y:0};function Np({previewOption:e={widthDimension:0}}){const n=t.exports.createRef(),[r,a]=t.exports.useState(!1),[l,o]=t.exports.useState({x:m(e),y:0}),[i,u]=t.exports.useState(85),s=t.exports.useCallback((function(e){if(!r)return;const t=e.shiftKey?10:1;"ArrowUp"===e.key?p({y:-1*t},!0):"ArrowDown"===e.key?p({y:t},!0):"ArrowLeft"===e.key?p({x:-1*t},!0):"ArrowRight"===e.key&&p({x:t},!0)}),[l,r]);if(t.exports.useEffect((()=>(document.addEventListener("keydown",s),()=>{document.removeEventListener("keydown",s)})),[s]),t.exports.useEffect((()=>(p({x:m(e),y:0}),window.addEventListener("message",h),()=>window.removeEventListener("message",h))),[e.widthDimension]),!e)return;const c=!e.url,f=[];!c&&r&&f.push("active"),c&&f.push("disabled");return M.createElement(M.Fragment,null,M.createElement(_p,{onClick:()=>{a(!r)},className:f.join(" "),disabled:c}),r&&!c&&M.createElement(M.Fragment,null,M.createElement("input",{type:"range",value:i,min:"0",max:"100",onChange:e=>{u(e.target.value)}}),M.createElement(Pp,{onMouseUp:e=>function(e){const t=n.current;p({x:t.offsetLeft,y:t.offsetTop}),document.body.removeEventListener("mousemove",d)}(),style:{opacity:i/100}},M.createElement("img",{src:e.url,alt:"",ref:n,onMouseDown:e=>function(e){zp.x=e.clientX,zp.y=e.clientY,document.body.addEventListener("mousemove",d)}(e),draggable:!1,style:{top:l.y+"px",left:l.x+"px"}}))));function d(e){const t=n.current;if(t){const n={x:t.offsetLeft-(zp.x-e.clientX),y:t.offsetTop-(zp.y-e.clientY)};t.style.left=n.x+"px",t.style.top=n.y+"px",zp.x=e.clientX,zp.y=e.clientY}}function p({x:e,y:t},n=!1){e=void 0===e?l.x:n?l.x+e:e,t=void 0===t?l.y:n?l.y+t:t,o({x:e,y:t})}function m(e){if(!e)return 0;return window.innerWidth/2-e.widthDimension/2-7}function h(t){"responsiveUpdate"===t.data&&"100%"===window.responsiveState.breakpoint&&p({x:m(e),y:0})}}function Tp(e={}){e.rootAttributes=e.rootAttributes??{};const[n,r]=t.exports.useState({dataName:"default",data:{},dataText:"{}",dataOptions:[],designPreview:[],errorMessage:null,loading:!1}),[a,l]=t.exports.useState(f(n.dataName,n.designPreview)),o=e=>r(Object.assign({},n,e)),[i,u]=t.exports.useState(!1);t.exports.useEffect((async()=>{await p(n.dataName)}),[]);const s=t.exports.useCallback((e=>{vp(e)&&c()}),[]);t.exports.useEffect((()=>(document.addEventListener("keydown",s),()=>{document.removeEventListener("keydown",s)})),[s]),t.exports.useEffect((()=>(window.addEventListener("message",d),()=>window.removeEventListener("message",d))),[n]),t.exports.useEffect((()=>{l(f(n.dataName,n.designPreview))}),[n.designPreview]);return M.createElement("div",{style:{display:"flex",gap:"1rem",alignItems:"center"}},M.createElement(xp,{onClick:()=>(u(!0),void setTimeout((()=>document.querySelector(".sidebar-active").focus()))),title:"Open a Sidebar with Data Options"}),M.createElement(Np,{previewOption:a}),M.createElement(wp,{className:i?"active sidebar-active":"",tabIndex:"0",onBlur:async e=>await gp(e)?c():null},M.createElement(Sp,null,M.createElement(Cp,{onClick:()=>c()})),n.dataOptions&&!!n.dataOptions.length&&M.createElement(Ep,null,M.createElement("label",{htmlFor:"data-options"},"Data Options"),M.createElement("select",{name:"data",id:"data-options",onChange:e=>async function(e){const t=e.target.value;await p(t)}(e),value:n.dataName,disabled:n.loading},n.dataOptions.map((e=>{const t=n.dataName===e;return M.createElement("option",{value:e,selected:t},e)})))),n.data&&M.createElement("textarea",{value:n.dataText,onChange:function(e){let t;try{t=JSON.parse(e.target.value)}catch(t){return void o({dataText:e.target.value,errorMessage:"Invalid JSON, please review and try again."})}o({dataText:e.target.value,data:t,errorMessage:null}),m(t)},disabled:n.loading}),n.errorMessage&&M.createElement("p",{className:"alert alert--error"},n.errorMessage),n.loading&&M.createElement("p",{className:"alert"},"Loading, please wait..."),M.createElement("div",{className:"actions"},M.createElement("button",{className:"btn btn--secondary",disabled:n.loading,onClick:e=>function(e,t){e.stopPropagation(),"string"!=typeof t&&(t=JSON.stringify(t,null,2));if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(t);{let n=document.createElement("textarea");return n.value=t,n.style.position="fixed",n.style.left="-999999px",n.style.top="-999999px",document.body.appendChild(n),n.select(),new Promise(((t,r)=>{document.execCommand("copy")?t():r(),n.remove(),e.target.focus()}))}}(e,n.data)},"Copy to Clipboard"),M.createElement("button",{className:"btn btn--secondary",disabled:n.loading,onClick:e=>function(){const e="https://blocks-registery.axe-web.com/content-generator/",t=new Headers;t.append("Content-Type","application/json");const r={method:"POST",headers:t,body:JSON.stringify({json:n.data})};return o({loading:!0,errorMessage:null}),fetch(e,r).then((e=>e.json())).then((e=>{if(console.log(e),200!==e.statusCode)throw new Error(e.message);const t=e.variation;o({dataText:JSON.stringify(t,null,2),data:t,errorMessage:null,loading:!1}),m(t)})).catch((e=>{o({loading:!1,errorMessage:"Something went wrong, please try again."})}))}(n.data)},"Generate Test"))));function c(){u(!1)}function f(e,t=[]){const n=t.filter((t=>t.dataSource===e));n.sort(((e,t)=>t.widthDimension-e.widthDimension));let r=window.responsiveState.breakpoint;return"100%"===r&&(r=window.innerWidth),n.find((e=>r>=e.widthDimension))}function d(e){"responsiveUpdate"===e.data&&l(f(n.dataName,n.designPreview))}async function p(e){const t=await async function(e="default"){const t=new URLSearchParams({name:e,block:window.devTool.blockName}),n=await fetch(`/data?${t}`);return await n.json()}(e);m(t.data);const n=Object.assign({errorMessage:null},t,{dataName:e},{dataText:JSON.stringify(t.data,null,2)});o(n)}function m(t){e.rootAttributes.previewFrame.contentWindow.postMessage("dataUpdate:"+JSON.stringify(t||{}),"*")}}const Lp={previewFrame:document.getElementById("preview_frame")};!function(e){const t=document.createElement("div");document.querySelector(".page_toolbar__middle").prepend(t);const n=jc(t),r=M.createElement(bp,{rootAttributes:e});n.render(r)}(Lp),function(e){const t=document.createElement("div");document.querySelector(".page_toolbar__left").prepend(t);const n=jc(t),r=M.createElement(Tp,{rootAttributes:e});n.render(r)}(Lp),function(e){const t=document.createElement("div");t.setAttribute("id","publish-btn"),document.querySelector(".page_toolbar__right").append(t);const n=jc(t),r=M.createElement(kp,{rootAttributes:e});n.render(r)}(Lp); diff --git a/layouts/scripts/dist/sync.min.js b/layouts/scripts/dist/sync.min.js index aab0f62..7d925c5 100644 --- a/layouts/scripts/dist/sync.min.js +++ b/layouts/scripts/dist/sync.min.js @@ -18,4 +18,4 @@ function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"de * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -var $=n.exports,j=V.exports;function B(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t