{"version":3,"sources":["webpack:///./app/javascript/polyfill.js","webpack:///./app/javascript/use-mousetrap.js","webpack:///./app/javascript/designer/fabric/objects/RectMask.js","webpack:///./app/javascript/designer/fabric/index.js","webpack:///./app/javascript/designer/create-canvas.js","webpack:///./app/javascript/designer/context.js","webpack:///./app/javascript/designer/fabric-react.js","webpack:///./app/javascript/designer/buttons.js","webpack:///./app/javascript/designer/controls-components.js","webpack:///./app/javascript/designer/use-pickr.js","webpack:///./app/javascript/designer/color-picker.js","webpack:///./app/javascript/designer/layers.js","webpack:///./app/javascript/designer/canvas-controls.js","webpack:///./app/javascript/designer/object-controls.js","webpack:///./app/javascript/designer/fonts.js","webpack:///./app/javascript/designer/font-picker.js","webpack:///./app/javascript/designer/number-select.js","webpack:///./app/javascript/designer/text-align.js","webpack:///./app/javascript/designer/letter-spacing.js","webpack:///./app/javascript/designer/text-shadow-controls.js","webpack:///./app/javascript/designer/text-controls.js","webpack:///./app/javascript/designer/slider.js","webpack:///./app/javascript/designer/image-controls.js","webpack:///./app/javascript/designer/controls.js","webpack:///./app/javascript/hooks/use-dropdown.js","webpack:///./app/javascript/designer/toolbar.js","webpack:///./app/javascript/designer/crop-canvas.js","webpack:///./app/javascript/designer/frame-canvas.js","webpack:///./app/javascript/designer/canvas.js","webpack:///./app/javascript/designer/markup-parser.js","webpack:///./app/javascript/designer/index.js"],"names":["Element","prototype","CharacterData","DocumentType","forEach","item","hasOwnProperty","Object","defineProperty","configurable","enumerable","writable","value","this","parentNode","removeChild","useMousetrap","keys","callback","element","deps","Array","isArray","undefined","memoisedCallback","useCallback","useEffect","m","Mousetrap","bind","unbind","RectMask","fabric","util","createClass","Rect","type","originX","originY","fill","hasRotatingPoint","render","ctx","fillStyle","beginPath","rect","left","getScaledWidth","top","getScaledHeight","canvas","width","height","closePath","fromObject","object","_fromObject","extend","StaticCanvas","renderCanvas","objects","v","viewportTransform","path","clipPath","cancelRequestedRender","calcViewportBoundaries","clearContext","fire","clipTo","clipContext","framedObjects","filter","o","isFrame","nonFramedObjects","backgroundImage","_renderBackground","save","transform","_renderObjects","restore","backgroundColor","controlsAboveOverlay","interactive","drawControls","shouldCache","_transformDone","renderCache","forClipping","drawClipPathOnCanvas","_renderOverlay","Canvas","preserveObjectStacking","renderOnAddRemove","customLoadFromJSON","json","reviver","serialized","JSON","parse","clone","_this","customCallback","trigger","_enlivenObjects","enlivenedObjects","clear","_setBgOverlay","enlivenedCanvasClip","custom__setupCanvas","call","obj","index","insertAt","overlayImage","background","overlay","_setOptions","lockScalingFlip","lockUniScaling","lockSkewingX","lockSkewingY","centeredScaling","transparentCorners","cornerSize","isTouchSupported","cornerStyle","borderScaleFactor","cornerColor","borderColor","getId","id","Date","now","Math","floor","random","ActiveSelection","hasControls","Text","lockScalingY","_controlsVisibility","bl","br","tl","tr","mt","mb","ml","mr","mtr","defaultShadowColor","defaultShadow","color","blur","fontSize","offset","offsetX","offsetY","NUM_FRACTION_DIGITS","originalGetKlass","getKlass","namespace","klass","Error","createCanvas","fns","reduce","f","g","compose","withPreview","withSave","withCustomToObject","withHistory","withCopyPaste","withSnapping","fabricCanvas","preview","sku","medium","imageData","toDataURL","multiplier","uploadDesignFromDataUrl","then","designUrl","previewUrl","URL","searchParams","append","toString","renderAll","savePromise","markup","toObject","url","_toObject","lock","undo","redo","state","captureHistory","debounce","push","addHistory","on","length","pop","requestRenderAll","clearHistory","cancel","copy","selection","getActiveObject","cloned","_clipboard","paste","clonedObj","discardActiveObject","set","evented","forEachObject","add","setCoords","setActiveObject","target","x","getCenterPoint","y","abs","centerH","centerV","angle","straighten","ConfigContext","createContext","FabricContext","useCanvas","events","useReducer","forceUpdate","useContext","e","off","useSelection","useState","setSelection","setSelectionWithTarget","clearSelection","selectionFunctions","useSelectionFunctions","useSelectionProperty","property","getSelectionProperty","setValue","isActiveSelection","apply","applyFn","getProperty","getObjects","map","acc","p","inactiveClasses","red","green","blue","buttonStyleClasses","text","contained","activeClasses","gray","textClasses","default","sizeClasses","sm","ButtonBase","ref","buttonStyle","className","rest","classnames","Button","React","forwardRef","IconButtonBase","active","children","icon","iconProps","size","label","tooltipPosition","textStyle","iconAttributes","focusable","role","fixedWidth","SelectButtonWithRef","IconButton","SelectButton","useConfig","AdminOnly","isAdmin","CustomerOnly","LabelOnly","EngravingOnly","Label","description","MobileControl","done","title","renderTitleBar","onClick","MobileControlList","MobileControlSelect","options","selected","onChange","getOptionStyle","option","key","style","usePickr","pickrOptions","useRef","containerRef","pickrRef","el","inline","document","createElement","current","appendChild","pickr","Pickr","create","theme","useAsButton","components","opacity","hue","interaction","input","destroyAndRemove","colors","engrave_colors","MobileColorPicker","pickrOnChange","toRGBA","optionsRef","showAlways","ColorTd","lineHeight","paddingBottom","ColorSmall","ColorPicker","onClear","portalRef","ModalContext","container","slice","SortableLayers","SortableContainer","select","SortableLayer","SortableElement","tabIndex","GripLines","SortableHandle","ImageLayer","src","getSrc","maxHeight","maxWidth","href","download","rel","TextLayer","copied","setCopied","copyToClipboard","setTimeout","navigator","clipboard","writeText","Promise","reject","Layers","_objects","reverse","reverseIndex","idx","useDragHandle","lockAxis","lockToContainerEdges","onSortEnd","newIndex","oldIndex","moveTo","helperClass","helperContainer","DesktopControls","controlKeys","MobileControls","control","setControl","tab","setTab","open","MobileControlsMenu","name","MobileTab","MobileTabContent","BackgroundMenu","BackgroundColor","setBackgroundColor","BackgroundImage","setBackgroundImage","toggleBackgroundLock","lockBackground","onSuccess","res","filesUploaded","crossOrigin","actionOptions","imageDim","labelWidth","labelHeight","transformations","circle","rotate","crop","aspectRatio","force","customRender","onPick","checked","CanvasControls","BackToLayers","ObjectControls","rotateClockwise","rotateCClockwise","bringForward","sendBackwards","remove","moveHorizontal","inc","moveVertical","preventDefault","moveIncrement","ceil","window","webFonts","fonts","useFontFamily","family","includes","FontFaceObserver","load","MobileFontPicker","fontFamily","setFontFamily","sort","FontPicker","handleSelectedItemChange","selectedItem","useSelect","items","initialSelectedItem","onSelectedItemChange","isOpen","getToggleButtonProps","getMenuProps","highlightedIndex","getItemProps","onKeyDown","nativeEvent","stopPropagation","hidden","highlighted","getStateReducer","min","actionAndChanges","useCombobox","stateChangeTypes","InputBlur","changes","inputValue","props","initialInputValue","InputKeyDownEnter","parsed","parseInt","isNaN","MobileNumberSelect","step","decrement","max","increment","NumberSelect","initialValue","inputs","onIsOpenChange","stateReducer","getInputProps","getComboboxProps","alignments","TextAlignControl","textAlign","c","align","getLabelProps","spacings","normal","wide","wider","widest","getItem","spacing","LetterSpacingControl","charSpacing","setCharSpacing","TextShadowControls","shadow","setBlur","setOffsetX","setOffsetY","fontSizeOptions","setColor","setFontSize","isItalic","toggleItalic","isBold","toggleBold","isShadow","toggleShadow","setText","TextControl","isActive","setIsActive","keycode","onFocus","onBlur","TextControls","fontStyle","fontWeight","controlProps","setTextAlign","Slider","values","rangeProps","handleChange","roundedValues","roundedMax","renderTrack","getTrackBackground","renderThumb","ScaleControl","scaleX","maxHeightScale","maxWidthScale","maxScale","scale","ImageControl","cropImage","editFramedImage","isCroppable","isFramed","setSrc","cropX","cropY","scaleToWidth","replace","disableTransformer","maxSize","startUploadingWhenMaxFilesReached","imageMax","Image","ImageControls","Controls","selectionType","AddDropdown","addText","addImage","addFramedImage","getRootProps","suppressRefError","Instructions","setIsOpen","toggleRef","dropdownRef","handleEveryClick","event","contains","addEventListener","removeEventListener","toggleProps","dropdownProps","useDropdown","Toolbar","mode","cancelPreview","close","inPreviewMode","handlePreviewClick","nonNavIconClass","cx","getFullBounds","bounds","right","bottom","getConstrainedBounds","constraintBounds","padding","CropControls","node","onCrop","onCancel","createPortal","CropCanvas","canvasDimensions","controlsContainer","containerDimensions","canvasEl","fabricCanvasRef","cropObject","imageObject","getCanvas","initialize","uniScaleTransform","cropCanvas","dispose","clonedImage","canvasBounds","targetImageBounds","getBoundingRect","getOriginalSize","selectable","setPositionByOrigin","Point","scaleY","restoredImageBounds","croppableBounds","initialCropBounds","imageOverlay","inverted","absolutePositioned","cropArea","lockRotation","minScaleLimit","cropBounds","fullCroppableBounds","constrainedBounds","scaleRatio","setDimensions","cssOnly","imageBounds","imageCenterPoint","insertImage","finishEditClippingRect","removeClipping","onAdd","frameCanvas","invertedClipObject","clippingObject","clippingRect","aCoords","image","fromURL","oImg","rectScaledHeight","rectScaledWidth","initialState","isSaving","showSafeArea","cropTarget","frameTarget","reducer","action","Preview","onSave","onClose","dispatch","sideBarContainer","config","useResizeObserver","containerWidth","containerHeight","isInitialized","setIsInitialized","isLoading","setIsLoading","backstoreOnly","bleedBorder","strokeLineJoin","rx","hx","fontFaceObservers","resolve","all","useFabric","canvasRef","framedCancel","adminBleedHeight","setAdminBleedHeight","adminBleedWidth","setBleedAdminWidth","Provider","Textbox","border","position","zIndex","pointerEvents","normalizeObject","lablrMarginOffset","mask","leftDiff","topDiff","isBackgroundImageLike","normalizeAsBackgroundImage","widthExtra","letterSpacing","round","parser","design","templateImage","find","WebFont","classes","google","families","launchInModal","body","checkSku","confirm","ReactDOM","unmountComponentAtNode","focusOnProps","focusLock","size_array","bordeaux","square","teardrop","woodbox_single","woodbox_double","woodbox_triple","woodbox_magnum","woodbox_photo_single","woodbox_photo_double","woodbox_photo_triple","woodbox_photo_magnum","veuve","mini_square","console","log"],"mappings":"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","file":"js/17-8034390ebd33b9932f2a.chunk.js","sourcesContent":["import \"core-js/stable\"\n\n/*\n * Polyfill remove in IE (used by Pickr) dependency\n * in designer.\n */\n(function (arr) {\n  arr.forEach(function (item) {\n    if (item.hasOwnProperty('remove')) {\n      return;\n    }\n    Object.defineProperty(item, 'remove', {\n      configurable: true,\n      enumerable: true,\n      writable: true,\n      value: function remove() {\n        if (this.parentNode === null) {\n          return;\n        }\n        this.parentNode.removeChild(this);\n      }\n    });\n  });\n})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);\n","import { useCallback, useEffect } from \"react\"\nimport Mousetrap from \"mousetrap\"\n\nexport const useMousetrap = (keys, callback, element, deps = []) => {\n  if (Array.isArray(element)) {\n    deps = element\n    element = undefined\n  }\n\n  const memoisedCallback = useCallback(callback, deps)\n\n  useEffect(() => {\n    const m = element ? new Mousetrap(element) : Mousetrap\n    m.bind(keys, memoisedCallback)\n\n    return () => {\n      m.unbind(keys)\n    }\n  }, [memoisedCallback, keys, element])\n}\n","import { fabric } from \"fabric\"\n\nconst RectMask = fabric.util.createClass(fabric.Rect, {\n  type: \"rect-mask\",\n  originX: \"center\",\n  originY: \"center\",\n  fill: \"transparent\",\n  hasRotatingPoint: false,\n  render: function(ctx) {\n    // https://stackoverflow.com/a/11770000\n    // hahah wow lol, you can create an inverse shape by drawing\n    // two shapes in \"oposite\" directions (clockwise, counter clockwise)\n    // pretty neat hack tbh\n    ctx.fillStyle = \"rgba(255, 255, 255, 0.9)\"\n    ctx.beginPath()\n    ctx.rect(\n      this.left - this.getScaledWidth() / 2,\n      this.top - this.getScaledHeight() / 2,\n      this.getScaledWidth(),\n      this.getScaledHeight()\n    )\n    ctx.rect(this.canvas.width, 0, -this.canvas.width, this.canvas.height)\n    ctx.fill()\n    ctx.closePath()\n  }\n})\n\nRectMask.fromObject = (object, callback) => {\n  return fabric.Object._fromObject(\"RectMask\", object, callback)\n}\n\nexport default RectMask\n","import { fabric } from \"fabric\"\nimport RectMask from \"./objects/RectMask\"\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, {\n  renderCanvas: function(ctx, objects) {\n    var v = this.viewportTransform,\n      path = this.clipPath\n    this.cancelRequestedRender()\n    this.calcViewportBoundaries()\n    this.clearContext(ctx)\n    this.fire(\"before:render\", { ctx: ctx })\n    if (this.clipTo) {\n      fabric.util.clipContext(this, ctx)\n    }\n\n    /*\n     * This is a very simpe fix that renders frame images\n     * before the background. Its a quick fix for lablr-frame\n     * objects templates.\n     * AD\n     */\n    const framedObjects = objects.filter(o => o.isFrame)\n    const nonFramedObjects = objects.filter(o => !o.isFrame)\n\n    // Temporarily remove the background image and just render the\n    // background fill (if any)\n    const backgroundImage = this.backgroundImage\n    delete this.backgroundImage\n    this._renderBackground(ctx)\n    this.backgroundImage = backgroundImage\n\n    ctx.save()\n    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5])\n    // Render any framed objects (above the background fill but behind\n    // the background image)\n    this._renderObjects(ctx, framedObjects)\n    ctx.restore()\n\n    // Temporarily remove the background color and just render the\n    // background image (if any)\n    const backgroundColor = this.backgroundColor\n    delete this.backgroundColor\n    this._renderBackground(ctx)\n    this.backgroundColor = backgroundColor\n\n    ctx.save()\n    //apply viewport transform once for all rendering process\n    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5])\n\n    /*\n     * See above comment\n     * AD\n     */\n    this._renderObjects(ctx, nonFramedObjects)\n    ctx.restore()\n    if (!this.controlsAboveOverlay && this.interactive) {\n      this.drawControls(ctx)\n    }\n    if (this.clipTo) {\n      ctx.restore()\n    }\n    if (path) {\n      path.canvas = this\n      // needed to setup a couple of variables\n      path.shouldCache()\n      path._transformDone = true\n      path.renderCache({ forClipping: true })\n      this.drawClipPathOnCanvas(ctx)\n    }\n    this._renderOverlay(ctx)\n    if (this.controlsAboveOverlay && this.interactive) {\n      this.drawControls(ctx)\n    }\n    this.fire(\"after:render\", { ctx: ctx })\n  }\n})\n\n// Customizations\nfabric.util.object.extend(fabric.Canvas.prototype, {\n  preserveObjectStacking: true,\n  renderOnAddRemove: false,\n\n  // This is exactly the same as the overriden function except it calls\n  // custom__setupCanvas instead of __setupCanvas.\n  customLoadFromJSON: function(json, callback, reviver) {\n    if (!json) {\n      return\n    }\n\n    // serialize if it wasn't already\n    var serialized =\n      typeof json === \"string\"\n        ? JSON.parse(json)\n        : fabric.util.object.clone(json)\n\n    var _this = this,\n      clipPath = serialized.clipPath,\n      renderOnAddRemove = this.renderOnAddRemove\n\n    var customCallback = () => {\n      this.trigger(\"after:load\")\n      callback && callback()\n    }\n\n    this.trigger(\"before:load\")\n    this.renderOnAddRemove = false\n\n    delete serialized.clipPath\n\n    this._enlivenObjects(\n      serialized.objects,\n      function(enlivenedObjects) {\n        _this.clear()\n        _this._setBgOverlay(serialized, function() {\n          if (clipPath) {\n            _this._enlivenObjects([clipPath], function(enlivenedCanvasClip) {\n              _this.clipPath = enlivenedCanvasClip[0]\n              _this.custom__setupCanvas.call(\n                _this,\n                serialized,\n                enlivenedObjects,\n                renderOnAddRemove,\n                customCallback\n              )\n            })\n          } else {\n            _this.custom__setupCanvas.call(\n              _this,\n              serialized,\n              enlivenedObjects,\n              renderOnAddRemove,\n              customCallback\n            )\n          }\n        })\n      },\n      reviver\n    )\n    return this\n  },\n\n  // The only difference between this and the original fn is this version\n  // doesn't call renderAll before the callback. This let's us load web fonts\n  // and the canvas in parallel and call one render when it's all ready.\n  // Otherwise if the canvas is rendered before the webfonts are loaded they\n  // won't display, and we'd need to mark the text objects as dirty to be able\n  // to re-render them with the web font displalying.\n  custom__setupCanvas: function(\n    serialized,\n    enlivenedObjects,\n    renderOnAddRemove,\n    callback\n  ) {\n    var _this = this\n    enlivenedObjects.forEach(function(obj, index) {\n      // we splice the array just in case some custom classes restored from JSON\n      // will add more object to canvas at canvas init.\n      _this.insertAt(obj, index)\n    })\n    this.renderOnAddRemove = renderOnAddRemove\n    // remove parts i cannot set as options\n    delete serialized.objects\n    delete serialized.backgroundImage\n    delete serialized.overlayImage\n    delete serialized.background\n    delete serialized.overlay\n    // this._initOptions does too many things to just\n    // call it. Normally loading an Object from JSON\n    // create the Object instance. Here the Canvas is\n    // already an instance and we are just loading things over it\n    this._setOptions(serialized)\n    callback && callback()\n  }\n})\n\nfabric.util.object.extend(fabric.Object.prototype, {\n  lockScalingFlip: true,\n  lockUniScaling: true,\n  lockSkewingX: true,\n  lockSkewingY: true,\n  centeredScaling: true,\n  transparentCorners: false,\n  cornerSize: fabric.isTouchSupported ? 25 : 20,\n  cornerStyle: \"circle\",\n  borderScaleFactor: 4,\n  cornerColor: \"rgba(0,0,0,0.5)\",\n  borderColor: \"#999999\",\n  getId: function() {\n    if (!this.id) {\n      this.id = \"id_\" + Date.now() + Math.floor(Math.random() * 1000)\n    }\n    return this.id\n  }\n})\n\nfabric.util.object.extend(fabric.ActiveSelection.prototype, {\n  hasControls: true\n})\n\nfabric.util.object.extend(fabric.Text.prototype, {\n  lockUniScaling: false,\n  lockScalingY: true,\n  _controlsVisibility: {\n    bl: false,\n    br: false,\n    tl: false,\n    tr: false,\n    mt: false,\n    mb: false,\n    ml: true,\n    mr: true,\n    mtr: true\n  },\n  defaultShadowColor: \"rgba(0,0,0,0.2)\",\n  defaultShadow: function(color = this.defaultShadowColor) {\n    const blur = 2 + Math.floor(this.fontSize * 0.06)\n    const offset = 1 + Math.floor(this.fontSize * 0.03)\n\n    return {\n      color: color,\n      offsetX: offset,\n      offsetY: offset,\n      blur\n    }\n  }\n})\n\n// Classes ------------------------------------------------------\nfabric.RectMask = RectMask\nfabric.Object.NUM_FRACTION_DIGITS = 4\n\n// Util ---------------------------------------------------------\n\nconst originalGetKlass = fabric.util.getKlass\nfabric.util.object.extend(fabric.util, {\n  getKlass: (type, namespace) => {\n    const klass = originalGetKlass(type, namespace)\n    if (klass === undefined) {\n      throw new Error(`Could not get class \"${type}\"`)\n    }\n    return klass\n  }\n})\n\nexport default fabric\n","import debounce from \"lodash/debounce\"\nimport fabric from \"./fabric\"\nimport { uploadDesignFromDataUrl } from \"./save-to-s3\"\n\n// There's no reason for doing this with compose, it could probably be done in\n// a simpler way, this was just the thing that came to mind.\nconst compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)))\n\nexport const createCanvas = () =>\n  compose(\n    withPreview,\n    withSave,\n    withCustomToObject,\n    withHistory,\n    withCopyPaste,\n    withSnapping\n  )(new fabric.Canvas())\n\nconst withPreview = fabricCanvas => {\n  fabricCanvas.preview = (sku, medium) => {\n    const imageData = fabricCanvas.toDataURL({ multiplier: 0.33 })\n    return uploadDesignFromDataUrl(imageData, \"image/jpg\", true).then(\n      designUrl => {\n        const previewUrl = new URL(\"/preview\", \"https://www.personalwine.com\")\n\n        previewUrl.searchParams.append(\"sku\", sku)\n        previewUrl.searchParams.append(\"medium\", medium)\n        previewUrl.searchParams.append(\"design_url\", designUrl)\n\n        return previewUrl.toString()\n      }\n    )\n  }\n\n  return fabricCanvas\n}\n\nconst withSave = fabricCanvas => {\n  /*\n   * The clippping path on the canvas is added to show the label area\n   * after accounting for what will be lost by the bleed. We clear it\n   * before saving to generate the print file which needs to include\n   * this bleed area.\n   *\n   * Optmization note:\n   * Export the canvas to image data, kick off the request to save\n   * the image on S3, while that's happening serialize the canvas,\n   * and once the image is saved return the serialization and url.\n   */\n  fabricCanvas.save = () => {\n    if (fabricCanvas.clipPath) {\n      fabricCanvas.clipPath = null\n      fabricCanvas.renderAll()\n    }\n\n    const imageData = fabricCanvas.toDataURL()\n    const savePromise = uploadDesignFromDataUrl(imageData, \"image/png\")\n    const markup = fabricCanvas.toObject()\n\n    return savePromise.then(url => ({ markup, url }))\n  }\n\n  return fabricCanvas\n}\n\n// Overwrite toObject to include our custom properties\nconst withCustomToObject = fabricCanvas => {\n  const _toObject = fabricCanvas.toObject.bind(fabricCanvas)\n\n  fabricCanvas.toObject = () =>\n    _toObject([\n      \"labelHeight\",\n      \"labelWidth\",\n      \"locked\",\n      \"lockBackground\",\n      \"isFrame\",\n      \"evented\"\n    ])\n\n  return fabricCanvas\n}\n\nconst withHistory = fabricCanvas => {\n  var lock = false\n  var undo = []\n  var redo = []\n  var state = fabricCanvas.toObject()\n\n  const captureHistory = debounce(() => {\n    undo.push(state)\n    redo = []\n    state = fabricCanvas.toObject()\n  }, 300)\n\n  const addHistory = () => !lock && captureHistory()\n\n  fabricCanvas.on(\"object:modified\", addHistory)\n  fabricCanvas.on(\"object:rotated\", addHistory)\n  fabricCanvas.on(\"object:added\", addHistory)\n  fabricCanvas.on(\"object:removed\", addHistory)\n\n  fabricCanvas.undo = () => {\n    if (undo.length > 0 && !lock) {\n      redo.push(state)\n      state = undo.pop()\n\n      lock = true\n      fabricCanvas.customLoadFromJSON(state, () => {\n        fabricCanvas.requestRenderAll()\n        lock = false\n      })\n    }\n  }\n\n  fabricCanvas.redo = () => {\n    if (redo.length > 0 && !lock) {\n      undo.push(state)\n      state = redo.pop()\n\n      lock = true\n      fabricCanvas.customLoadFromJSON(state, () => {\n        fabricCanvas.requestRenderAll()\n        lock = false\n      })\n    }\n  }\n\n  fabricCanvas.clearHistory = () => {\n    captureHistory.cancel()\n    undo = []\n    redo = []\n    state = fabricCanvas.toObject()\n  }\n\n  return fabricCanvas\n}\n\nconst withCopyPaste = fabricCanvas => {\n  fabricCanvas.copy = () => {\n    const selection = fabricCanvas.getActiveObject()\n\n    if (selection) {\n      selection.clone(function(cloned) {\n        fabricCanvas._clipboard = cloned\n      })\n    }\n  }\n\n  fabricCanvas.paste = () => {\n    if (fabricCanvas._clipboard) {\n      fabricCanvas._clipboard.clone(function(clonedObj) {\n        fabricCanvas.discardActiveObject()\n        clonedObj.set({\n          left: clonedObj.left + 10,\n          top: clonedObj.top + 10,\n          evented: true\n        })\n        if (clonedObj.type === \"activeSelection\") {\n          // active selection needs a reference to the canvas.\n          clonedObj.canvas = fabricCanvas\n          clonedObj.forEachObject(function(obj) {\n            fabricCanvas.add(obj)\n          })\n          // this should solve the unselectability\n          clonedObj.setCoords()\n        } else {\n          fabricCanvas.add(clonedObj)\n        }\n        fabricCanvas._clipboard.top += 10\n        fabricCanvas._clipboard.left += 10\n        fabricCanvas.setActiveObject(clonedObj)\n        fabricCanvas.requestRenderAll()\n      })\n    }\n  }\n\n  return fabricCanvas\n}\n\nconst withSnapping = fabricCanvas => {\n  // Add horizontal and vertical snapping when an object is being dragged\n  // in bordeaux sizes the height is much greater than the width so the\n  // snap threshold needs to be smaller. Will eventually need a more elegant\n  // way to get snapThresholdY based on canvas size.\n  const snapThresholdX = 0.05\n  const snapThresholdY = 0.02\n\n  fabricCanvas.on(\"object:moving\", function({ target }) {\n    const x = target.getCenterPoint().x\n    const y = target.getCenterPoint().y\n    if (\n      Math.abs(x - target.canvas.width / 2) <\n      target.canvas.width * snapThresholdX\n    ) {\n      target.centerH().setCoords()\n    }\n\n    if (\n      Math.abs(y - target.canvas.height / 2) <\n      target.canvas.height * snapThresholdY\n    ) {\n      target.centerV().setCoords()\n    }\n  })\n\n  // Add rotation snapping\n  const rotationSnapThreshold = 9\n\n  fabricCanvas.on(\"object:rotating\", ({ target }) => {\n    if (\n      target.angle % 90 < rotationSnapThreshold ||\n      target.angle % 90 > 90 - rotationSnapThreshold\n    ) {\n      target.straighten()\n    }\n  })\n\n  return fabricCanvas\n}\n","import { createContext } from \"react\"\n\nexport const ConfigContext = createContext()\nexport const FabricContext = createContext(null)\n","import {\n  useCallback,\n  useContext,\n  useEffect,\n  useReducer,\n  useRef,\n  useState\n} from \"react\"\nimport FontFaceObserver from \"fontfaceobserver\"\nimport { createCanvas } from \"./create-canvas\"\nimport { FabricContext } from \"./context\"\nimport fabric from \"./fabric\"\n\nexport const useFabric = ({ markup, medium, isAdmin }) => {\n  const canvasEl = useRef()\n  const fabricCanvasRef = useRef(null)\n  const [isInitialized, setIsInitialized] = useState(false)\n  const [isLoading, setIsLoading] = useState(false)\n\n  /*\n   * This function prevents the running the createCanvas\n   * function on every render.\n   */\n  const getCanvas = () => {\n    if (fabricCanvasRef.current === null) {\n      fabricCanvasRef.current = createCanvas()\n    }\n\n    return fabricCanvasRef.current\n  }\n\n  /*\n   * Initial canvas setup\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n\n    canvas.initialize(canvasEl.current, {\n      height: 0,\n      width: 0\n    })\n\n    canvas.on(\"before:load\", () => setIsLoading(true))\n    canvas.on(\"after:load\", () => setIsLoading(false))\n\n    return () => canvas.dispose()\n  }, [])\n\n  /*\n   * Load specific markup into the canvas\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n\n    canvas.setDimensions(\n      {\n        width: markup.labelWidth,\n        height: markup.labelHeight\n      },\n      { backstoreOnly: true }\n    )\n\n    if (medium === \"label\" && !isAdmin) {\n      const bleedBorder = 19\n\n      canvas.clipPath = new fabric.Rect({\n        top: bleedBorder,\n        left: bleedBorder,\n        width: canvas.width - bleedBorder * 2,\n        height: canvas.height - bleedBorder * 2,\n        strokeLineJoin: \"round\",\n        rx: 8,\n        hx: 8\n      })\n    }\n\n    // Load all font families present in the markup. First, we collect\n    // unique, truthy font family values from the objects in the canvas.\n    // Then we map over those values returning a Promise that will resolve\n    // regardless of load outcome.\n    //\n    // TODO move this, and the code below, into the fabric library\n    const fontFaceObservers = markup.objects\n      .reduce(\n        (acc, o) =>\n          o.fontFamily && !acc.includes(o.fontFamily)\n            ? [...acc, o.fontFamily]\n            : acc,\n        []\n      )\n      .map(fontFamily => {\n        const observer = new FontFaceObserver(fontFamily)\n\n        // Return a promise that will resolve regardless of if the\n        // font loaded or not\n        return observer.load().catch(() => {\n          Promise.resolve()\n        })\n      })\n\n    Promise.all(fontFaceObservers).then(() => {\n      // Load the markup into the canvas once all the web fonts have\n      // loaded (regardless of success or failure).\n      //\n      // TODO a performance optimization would be to start loading the\n      // canvas before font families have loaded to run these processes\n      // in parallel (as the canvas loading will most likely be loading\n      // images). In my first attempts the canvas wasn't redrawing even\n      // with an explicit call to render all.\n      canvas.customLoadFromJSON(markup, () => {\n        canvas.clearHistory()\n        canvas.requestRenderAll()\n        setIsInitialized(true)\n      })\n    })\n  }, [markup, medium])\n\n  return [canvasEl, getCanvas(), isInitialized, isLoading]\n}\n\n// See https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate\nexport const useCanvas = (events = [\"load\"]) => {\n  const [, forceUpdate] = useReducer(x => x + 1, 0)\n  const canvas = useContext(FabricContext)\n\n  useEffect(() => {\n    if (canvas) {\n      events.forEach(e => canvas.on(e, forceUpdate))\n      return () => events.forEach(e => canvas.off(e, forceUpdate))\n    }\n  }, [canvas, events, forceUpdate])\n\n  return canvas\n}\n\nexport const useSelection = () => {\n  const canvas = useContext(FabricContext)\n  const [selection, setSelection] = useState(null)\n\n  useEffect(() => {\n    const setSelectionWithTarget = ({ target }) => setSelection(target)\n    const clearSelection = () => setSelection(null)\n\n    canvas.on(\"selection:created\", setSelectionWithTarget)\n    canvas.on(\"selection:updated\", setSelectionWithTarget)\n    canvas.on(\"selection:cleared\", clearSelection)\n\n    return () => {\n      canvas.off(\"selection:created\", setSelectionWithTarget)\n      canvas.off(\"selection:updated\", setSelectionWithTarget)\n      canvas.off(\"selection:cleared\", clearSelection)\n    }\n  }, [canvas])\n\n  const selectionFunctions = useSelectionFunctions(selection)\n\n  return { canvas, selection, ...selectionFunctions }\n}\n\nexport const useSelectionProperty = (\n  selection,\n  property,\n  events = [\"modified\"]\n) => {\n  const [value, setValue] = useState(getSelectionProperty(selection, property))\n\n  useEffect(() => {\n    const set = () => setValue(getSelectionProperty(selection, property))\n\n    // Selection or property has changed so we need to set the value\n    set()\n\n    if (selection.type === \"activeSelection\") {\n      selection.forEachObject(o => events.forEach(e => o.on(e, set)))\n      return () =>\n        selection.forEachObject(o => events.forEach(e => o.off(e, set)))\n    } else {\n      events.forEach(e => selection.on(e, set))\n      return () => events.forEach(e => selection.off(e, set))\n    }\n  }, [selection, property, events])\n\n  return value\n}\n\nconst useSelectionFunctions = selection => {\n  const isActiveSelection = selection && selection.type === \"activeSelection\"\n\n  const applyCallback = useCallback(applyFn => apply(selection, applyFn), [\n    selection\n  ])\n\n  const getSelectionPropertyCallback = useCallback(\n    property => getSelectionProperty(selection, property),\n    [selection]\n  )\n\n  return {\n    isActiveSelection,\n    apply: applyCallback,\n    getProperty: getSelectionPropertyCallback\n  }\n}\n\n/*\n * Returns a property value of selection. If the selection is\n * multiple objects it will return a value if all objects have\n * the same value or null otherwise.\n */\nconst getSelectionProperty = (selection, property) => {\n  const getProperty = o =>\n    typeof property === \"function\" ? property(o) : o[property]\n\n  return selection.type === \"activeSelection\"\n    ? selection\n        .getObjects()\n        .map(getProperty)\n        .reduce((acc, p) => (p === acc ? acc : null))\n    : getProperty(selection)\n}\n\n/*\n * Create a function to apply a change to a selection in a\n * consistent manner.\n */\nconst apply = (selection, applyFn) => {\n  if (selection.type === \"activeSelection\") {\n    selection.forEachObject(o => {\n      applyFn(o)\n      o.trigger(\"modified\")\n    })\n  } else {\n    applyFn(selection)\n    selection.trigger(\"modified\")\n  }\n\n  selection.canvas.trigger(\"object:modified\", { target: selection })\n  selection.canvas.requestRenderAll()\n}\n","import React, { forwardRef } from \"react\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport classnames from \"classnames\"\n\nconst inactiveClasses = {\n  red: \"surface-red\",\n  green: \"surface-green\",\n  blue: \"text-blue-700\"\n}\n\nconst buttonStyleClasses = {\n  text: \"button-text\",\n  contained: \"button-contained\"\n}\n\nconst activeClasses = {\n  gray: \"bg-blue-200 text-blue-700\"\n}\n\nconst textClasses = {\n  default: \"uppercase font-bold tracking-wide\"\n}\n\nconst sizeClasses = {\n  sm: \"text-sm\"\n}\n\nexport const ButtonBase = (\n  { buttonStyle = \"text\", className, ...rest },\n  ref\n) => {\n  return (\n    <button\n      ref={ref}\n      className={classnames(\n        \"button surface\",\n        buttonStyleClasses[buttonStyle],\n        className\n      )}\n      {...rest}\n    />\n  )\n}\n\nexport const Button = React.forwardRef(ButtonBase)\n\nconst IconButtonBase = (\n  {\n    active = false,\n    children,\n    className,\n    color = \"gray\",\n    icon,\n    iconProps = { size: \"lg\" },\n    label,\n    tooltipPosition = \"bottom\",\n    size,\n    textStyle = \"default\",\n    ...rest\n  },\n  ref\n) => {\n  // Make these buttons accessible.\n  // See https://www.sarasoueidan.com/blog/accessible-icon-buttons\n  //\n  // Setting focusable to false will prevent the icon itself from\n  // receiving focus in IE which means two tab stops for one button.\n  const iconAttributes = {\n    focusable: \"false\"\n  }\n\n  // If a child is provided, mark the icon as aria-hidden and let\n  // the text be used.\n  if (children) {\n    iconAttributes[\"aria-hidden\"] = true\n  }\n\n  // Use far as the default icon set\n  if (typeof icon === \"string\") {\n    icon = [\"far\", icon]\n  }\n\n  return (\n    <Button\n      {...rest}\n      {...(label && {\n        role: \"tooltip\",\n        \"aria-label\": label,\n        \"data-microtip-position\": tooltipPosition\n      })}\n      className={classnames(\n        className,\n        sizeClasses[size],\n        textClasses[textStyle],\n        active ? activeClasses[color] : inactiveClasses[color]\n      )}\n      ref={ref}\n    >\n      {icon && (\n        <FontAwesomeIcon\n          icon={icon}\n          fixedWidth\n          {...iconAttributes}\n          {...iconProps}\n        />\n      )}\n      {children && <> {children}</>}\n    </Button>\n  )\n}\n\nconst SelectButtonWithRef = ({ className, children, ...rest }, ref) => (\n  <IconButton\n    {...rest}\n    ref={ref}\n    className={classnames(className, \"whitespace-no-wrap\")}\n  >\n    {children}\n    <FontAwesomeIcon icon={[\"fas\", \"caret-down\"]} size=\"sm\" className=\"ml-px\" />\n  </IconButton>\n)\n\nexport const SelectButton = forwardRef(SelectButtonWithRef)\nexport const IconButton = forwardRef(IconButtonBase)\n","import React, { useContext } from \"react\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport { IconButton } from \"./buttons\"\nimport { ConfigContext } from \"./context\"\n\nexport const useConfig = () => useContext(ConfigContext)\n\nexport const AdminOnly = ({ children }) => {\n  const { isAdmin } = useConfig()\n\n  return isAdmin ? <>{children}</> : null\n}\n\nexport const CustomerOnly = ({ children }) => {\n  const { isAdmin } = useConfig()\n\n  return !isAdmin ? <>{children}</> : null\n}\n\nexport const LabelOnly = ({ children }) => {\n  const { medium } = useConfig()\n\n  return medium === \"label\" ? <>{children}</> : null\n}\n\nexport const EngravingOnly = ({ children }) => {\n  const { medium } = useConfig()\n\n  return medium === \"engraving\" ? <>{children}</> : null\n}\n\nexport const Label = ({ label, description }) => (\n  <div className=\"p-1\">\n    <div className=\"text-sm text-gray-600 font-bold\">{label}</div>\n  </div>\n)\n\nexport const MobileControl = ({ done, title, children, renderTitleBar }) => (\n  <>\n    <div className=\"px-4 py-2 border-b flex items-center justify-between\">\n      <div className=\"flex items-center\">\n        <IconButton\n          icon=\"arrow-left\"\n          iconProps={{ size: \"1x\" }}\n          onClick={done}\n          className=\"-ml-4 pl-4 w-8 box-content text-center\"\n        />\n        <div className=\"px-2\">{title}</div>\n      </div>\n      {renderTitleBar && renderTitleBar()}\n    </div>\n    {children}\n  </>\n)\n\nexport const MobileControlList = ({ children }) => (\n  <ul className=\"px-2\">{children({ className: \"px-12\" })}</ul>\n)\n\nexport const MobileControlSelect = ({\n  options,\n  selected,\n  onChange,\n  getOptionStyle\n}) => (\n  <ul className=\"h-40 overflow-y-auto\">\n    {options.map((option, index) => (\n      <li key={index}>\n        <button\n          onClick={() => onChange(option)}\n          className=\"flex w-full px-4 py-3\"\n        >\n          <div className=\"w-8 text-center\">\n            {option === selected && (\n              <FontAwesomeIcon\n                icon={[\"far\", \"check\"]}\n                className=\"text-blue-600\"\n              />\n            )}\n          </div>\n          <div\n            className=\"px-2\"\n            style={getOptionStyle ? getOptionStyle({ option }) : {}}\n          >\n            {option}\n          </div>\n        </button>\n      </li>\n    ))}\n  </ul>\n)\n","import { useEffect, useRef } from \"react\"\nimport Pickr from \"@simonwep/pickr\"\n\nexport const usePickr = (onChange, pickrOptions = {}) => {\n  const ref = useRef()\n  const containerRef = useRef()\n  const pickrRef = useRef()\n\n  useEffect(() => {\n    var el\n    if (pickrOptions.inline) {\n      /*\n       * Pickr manipulates the root element passed in via el and don't\n       * want it tampering with the DOM element controlled by React so\n       * we create a new div for it to render in.\n       */\n      el = document.createElement(\"div\")\n      ref.current.appendChild(el)\n    } else {\n      el = ref.current\n    }\n\n    const pickr = Pickr.create({\n      el,\n      theme: \"monolith\",\n      useAsButton: true,\n      components: {\n        preview: true,\n        opacity: true,\n        hue: true,\n        interaction: {\n          input: true\n        }\n      },\n      ...pickrOptions\n    })\n\n    pickrRef.current = pickr\n\n    return () => {\n      pickrRef.current = null\n      pickr.destroyAndRemove()\n    }\n  }, [ref, containerRef, pickrOptions])\n\n  useEffect(() => {\n    pickrRef.current.on(\"change\", onChange)\n\n    return () => {\n      // In the case where the component is unmounting, the\n      // pickr object will have already been destroyed.\n      if (pickrRef.current) {\n        pickrRef.current.off(\"change\", onChange)\n      }\n    }\n  }, [onChange])\n\n  return [ref]\n}\n","import React, { useCallback, useContext, useRef } from \"react\"\nimport { usePickr } from \"./use-pickr\"\nimport { IconButton } from \"./buttons\"\nimport { MobileControl, useConfig } from \"./controls-components\"\nimport { ModalContext } from \"../components/modal\"\n\nconst colors = [\n  \"#000000\",\n  \"#63563B\",\n  \"#92949B\",\n  \"#BABBBD\",\n  \"#F4E4C1\",\n  \"#FFFFFF\",\n  \"#A2242F\",\n  \"#DC793E\",\n  \"#FFD300\",\n  \"#74AA50\",\n  \"#006B54\",\n  \"#263056\",\n  \"#7781A4\",\n  \"#7BAFD4\",\n  \"#6C244C\",\n  \"#E6AF91\"\n]\n\nconst engrave_colors = [\"#000000\", \"#FFFFFF\"]\n\nconst ColorPicker = ({ onClear, onChange, value }) => {\n  const { medium } = useConfig()\n\n  /*\n   * Grab the modal container ref to render the color\n   * picker pop up in. Prevents any z-index overflow lock.\n   */\n  const { portalRef } = useContext(ModalContext)\n\n  /*\n   * Create a stable object for pickrOptions to prevent unnecessary re-renders\n   */\n  const optionsRef = useRef({\n    container: portalRef.current,\n    default: value\n  })\n\n  /*\n   * We call toString(0) to full round off all the values. If we ever choose\n   * to not support IE can remove this and let non-rounded colors be accepted.\n   */\n  const pickrOnChange = useCallback(\n    color => onChange(color.toRGBA().toString(0)),\n    [onChange]\n  )\n\n  const [ref] = usePickr(pickrOnChange, optionsRef.current)\n\n  return (\n    <>\n      {onClear && (\n        <IconButton\n          icon=\"tint-slash\"\n          size=\"sm\"\n          className=\"w-full text-left\"\n          onClick={onClear}\n        >\n          Clear\n        </IconButton>\n      )}\n      <table className=\"w-full\">\n        <tbody>\n          <tr className={medium === \"label\" ? \"\" : \"flex\"}>\n            {medium === \"label\"\n              ? colors\n                  .slice(0, 8)\n                  .map(color => (\n                    <ColorTd key={color} color={color} onChange={onChange} />\n                  ))\n              : engrave_colors.map(color => (\n                  <ColorSmall key={color} color={color} onChange={onChange} />\n                ))}\n          </tr>\n          <tr>\n            {medium === \"label\" &&\n              colors\n                .slice(8)\n                .map(color => (\n                  <ColorTd key={color} color={color} onChange={onChange} />\n                ))}\n          </tr>\n        </tbody>\n      </table>\n      <IconButton\n        icon=\"palette\"\n        size=\"sm\"\n        className={`w-full text-left ${\n          medium === \"label\" ? \"\" : \"hide-custom\"\n        }`}\n        ref={ref}\n      >\n        Custom\n      </IconButton>\n    </>\n  )\n}\n\nexport const MobileColorPicker = ({ done, title, onChange, value }) => {\n  const pickrOnChange = useCallback(\n    color => onChange(color.toRGBA().toString()),\n    [onChange]\n  )\n\n  /*\n   * Create a stable object for pickrOptions to prevent unnecessary re-renders\n   */\n  const optionsRef = useRef({\n    inline: true,\n    showAlways: true,\n    default: value\n  })\n\n  const [ref] = usePickr(pickrOnChange, optionsRef.current)\n\n  return (\n    <MobileControl done={done} title={title}>\n      <div className=\"p-2 mobile-pickr\">\n        <div ref={ref} />\n      </div>\n    </MobileControl>\n  )\n}\n\nconst ColorTd = ({ color, onChange }) => (\n  <td key={color} style={{ lineHeight: 0 }}>\n    <button\n      key={color}\n      className=\"w-full relative\"\n      onClick={() => onChange(color)}\n      style={{ paddingBottom: \"100%\" }}\n    >\n      <div\n        className=\"absolute inset-0 rounded-full border border-gray-700 sm:border-gray-300\"\n        style={{\n          backgroundColor: color\n        }}\n      />\n    </button>\n  </td>\n)\n\nconst ColorSmall = ({ color, onChange }) => (\n  <div key={color} style={{ lineHeight: 0 }}>\n    <button\n      key={color}\n      className=\"w-full relative small-color\"\n      onClick={() => onChange(color)}\n      style={{ paddingBottom: \"0 !important\" }}\n    >\n      <div\n        className=\"rounded-full border border-gray-700 sm:border-gray-300\"\n        style={{\n          backgroundColor: color,\n          height: \"30px\",\n          width: \"30px\"\n        }}\n      />\n    </button>\n  </div>\n)\n\nexport default ColorPicker\n","import React, { useRef, useState } from \"react\"\nimport {\n  SortableContainer,\n  SortableElement,\n  SortableHandle\n} from \"react-sortable-hoc\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport classnames from \"classnames\"\nimport { useCanvas, useSelectionProperty } from \"./fabric-react\"\nimport { IconButton } from \"./buttons\"\nimport { AdminOnly } from \"./controls-components\"\n\nconst Layers = () => {\n  const ref = useRef()\n  const canvas = useCanvas([\"load\", \"object:modified\"])\n  const objects = canvas._objects.slice(0).reverse()\n  const select = o => canvas.setActiveObject(o).requestRenderAll()\n\n  const reverseIndex = idx => objects.length - 1 - idx\n  const onSortEnd = ({ newIndex, oldIndex }) => {\n    const object = canvas.item(reverseIndex(oldIndex))\n    canvas.moveTo(object, reverseIndex(newIndex))\n    canvas.trigger(\"object:modified\").requestRenderAll()\n  }\n\n  return (\n    <>\n      <SortableLayers\n        select={select}\n        objects={objects}\n        useDragHandle={true}\n        lockAxis=\"y\"\n        lockToContainerEdges={true}\n        onSortEnd={onSortEnd}\n        helperClass=\"shadow\"\n        helperContainer={() => ref.current}\n      />\n      <ul ref={ref} />\n    </>\n  )\n}\n\nconst SortableLayers = SortableContainer(({ objects, select }) => (\n  <ul className=\"bg-gray-200\">\n    {objects.map((object, index) => (\n      <SortableLayer\n        key={`item-${object.getId()}`}\n        index={index}\n        object={object}\n        select={select}\n      />\n    ))}\n  </ul>\n))\n\nconst SortableLayer = SortableElement(({ select, object }) => (\n  <li tabIndex=\"0\" className=\"bg-white\">\n    <div className={classnames(\"flex justify-between items-center p-1-h\")}>\n      <GripLines />\n      {(() => {\n        switch (object.type) {\n          case \"image\":\n            return <ImageLayer select={() => select(object)} object={object} />\n          case \"textbox\":\n            return <TextLayer select={() => select(object)} object={object} />\n          default:\n            return null\n        }\n      })()}\n    </div>\n  </li>\n))\n\nconst GripLines = SortableHandle(() => (\n  <div className=\"p-3 cursor-move\">\n    <FontAwesomeIcon icon={[\"far\", \"grip-lines\"]} className=\"text-gray-600\" />\n  </div>\n))\n\nconst ImageLayer = ({ select, object }) => {\n  const src = useSelectionProperty(object, o => o.getSrc())\n\n  return (\n    <>\n      <button onClick={select} className=\"p-2 flex-1 flex items-center\">\n        <img\n          src={src}\n          className=\"-my-2 rounded\"\n          style={{ maxHeight: \"2.5rem\", maxWidth: \"5rem\" }}\n        />\n      </button>\n      <AdminOnly>\n        <a\n          href={src}\n          download\n          className=\"button text-blue-600\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n        >\n          <FontAwesomeIcon icon={[\"far\", \"download\"]} fixedWidth />\n        </a>\n      </AdminOnly>\n    </>\n  )\n}\n\nconst TextLayer = ({ select, object }) => {\n  const text = useSelectionProperty(object, \"text\")\n\n  const [copied, setCopied] = useState(false)\n  const copy = () =>\n    copyToClipboard(text)\n      .then(() => {\n        setCopied(true)\n        setTimeout(() => setCopied(false), 2500)\n      })\n      .catch(() => {})\n\n  return (\n    <>\n      <button\n        className=\"p-2 flex-1 flex items-center text-left truncate\"\n        onClick={select}\n      >\n        <div>{text}</div>\n      </button>\n      <AdminOnly>\n        <IconButton\n          size=\"sm\"\n          icon={copied ? \"check\" : \"copy\"}\n          color={copied && \"green\"}\n          onClick={copy}\n        />\n      </AdminOnly>\n    </>\n  )\n}\n\nconst copyToClipboard = text =>\n  navigator.clipboard ? navigator.clipboard.writeText(text) : Promise.reject()\n\nexport default Layers\n","import React, { useCallback, useState } from \"react\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport classnames from \"classnames\"\nimport { MobileControl, MobileControlList } from \"./controls-components\"\nimport FileUploader from \"./file-uploader\"\nimport { IconButton } from \"./buttons\"\nimport {\n  AdminOnly,\n  CustomerOnly,\n  Label,\n  LabelOnly,\n  useConfig\n} from \"./controls-components\"\nimport { useCanvas } from \"./fabric-react\"\nimport ColorPicker, { MobileColorPicker } from \"./color-picker\"\nimport Layers from \"./layers\"\n\nconst CanvasControls = () => {\n  return (\n    <>\n      <div className=\"sm:hidden\">\n        <MobileControls />\n      </div>\n      <div className=\"hidden sm:block\">\n        <DesktopControls />\n      </div>\n    </>\n  )\n}\n\nconst DesktopControls = () => {\n  return (\n    <div className=\"divide-y\">\n      <div>\n        <div className=\"p-1\">\n          <Label label=\"Layers\" description=\"Select a layer to edit\" />\n        </div>\n        <Layers />\n      </div>\n      <LabelOnly>\n        <div className=\"p-1\">\n          <Label label=\"Background Color\" />\n          <BackgroundColor />\n        </div>\n      </LabelOnly>\n      <div className=\"p-1\">\n        <BackgroundImage />\n      </div>\n    </div>\n  )\n}\n\nconst controlKeys = {\n  backgroundImage: \"Background Image\",\n  backgroundColor: \"Background Color\"\n}\n\nconst MobileControls = () => {\n  const [control, setControl] = useState(null)\n  const [tab, setTab] = useState(\"layers\")\n\n  if (!control) {\n    return <MobileControlsMenu open={setControl} tab={tab} setTab={setTab} />\n  }\n\n  const done = () => setControl(null)\n\n  switch (control) {\n    case controlKeys.backgroundImage:\n      return <BackgroundImage done={done} />\n    case controlKeys.backgroundColor:\n      return <BackgroundColor done={done} />\n    default:\n      throw new Error(`Invalid control ${control}`)\n  }\n}\n\nconst MobileControlsMenu = ({ open, tab, setTab }) => {\n  return (\n    <>\n      <div className=\"flex\">\n        <MobileTab active={tab} name=\"layers\" set={setTab}>\n          Layers\n        </MobileTab>\n        <MobileTab active={tab} name=\"background\" set={setTab}>\n          Background\n        </MobileTab>\n      </div>\n      <div className=\"overflow-y-auto\" style={{ height: \"11rem\" }}>\n        <MobileTabContent active={tab} name=\"background\">\n          <BackgroundMenu open={open} />\n        </MobileTabContent>\n        <MobileTabContent active={tab} name=\"layers\">\n          <Layers />\n        </MobileTabContent>\n      </div>\n    </>\n  )\n}\n\nconst MobileTab = ({ active, name, set, ...rest }) => (\n  <button\n    className={classnames(\n      \"flex-1 p-3 text-center border-b-2\",\n      \"focus:outline-none\",\n      active === name && \"border-blue-600\"\n    )}\n    onClick={() => set(name)}\n    {...rest}\n  />\n)\n\nconst MobileTabContent = ({ active, name, ...rest }) => (\n  <div className={classnames(active !== name && \"hidden\")} {...rest} />\n)\n\nconst BackgroundMenu = ({ open }) => {\n  const canvas = useCanvas([\"load\", \"background:modified\"])\n\n  return (\n    <ul className=\"divide-y\">\n      <li className=\"p-1\">\n        <button\n          className=\"w-full p-2 flex items-center justify-between\"\n          onClick={() => open(controlKeys.backgroundImage)}\n        >\n          <div>Image</div>\n          <FontAwesomeIcon icon={[\"far\", \"chevron-right\"]} fixedWidth />\n        </button>\n      </li>\n      <AdminOnly>\n        <LabelOnly>\n          <li className=\"p-1\">\n            <button\n              className=\"w-full p-2 flex items-center justify-between\"\n              onClick={() => open(controlKeys.backgroundColor)}\n            >\n              <div>Color</div>\n              <div className=\"flex items-center\">\n                <div\n                  className=\"inline-block w-8 h-8 -my-2 mr-2 rounded-full border\"\n                  style={{ backgroundColor: canvas.backgroundColor }}\n                />\n                <FontAwesomeIcon icon={[\"far\", \"chevron-right\"]} fixedWidth />\n              </div>\n            </button>\n          </li>\n        </LabelOnly>\n      </AdminOnly>\n    </ul>\n  )\n}\n\nconst BackgroundColor = ({ done }) => {\n  const canvas = useCanvas([\"load\", \"background:modified\"])\n\n  const setBackgroundColor = useCallback(\n    color => {\n      canvas.setBackgroundColor(color, () => {\n        canvas.trigger(\"object:modified\")\n        canvas.trigger(\"background:modified\")\n        canvas.requestRenderAll()\n      })\n    },\n    [canvas]\n  )\n\n  const clear = useCallback(() => {\n    canvas.setBackgroundColor(\"white\", () => {\n      canvas.trigger(\"object:modified\")\n      canvas.trigger(\"background:modified\")\n      canvas.requestRenderAll()\n    })\n  }, [canvas])\n\n  return (\n    <>\n      <div className=\"hidden sm:block\">\n        <ColorPicker\n          value={canvas.backgroundColor}\n          onClear={clear}\n          onChange={setBackgroundColor}\n        />\n      </div>\n      <div className=\"sm:hidden\">\n        <MobileColorPicker\n          done={done}\n          title=\"Background color\"\n          value={canvas.backgroundColor}\n          onChange={setBackgroundColor}\n        />\n      </div>\n    </>\n  )\n}\n\nconst BackgroundImage = ({ done }) => {\n  const canvas = useCanvas([\"load\", \"background:modified\", \"config:modified\"])\n\n  const set = res => {\n    if (res.filesUploaded.length > 0) {\n      canvas.setBackgroundImage(\n        res.filesUploaded[0].url,\n        () => {\n          canvas.trigger(\"background:modified\")\n          canvas.trigger(\"object:modified\")\n          canvas.requestRenderAll()\n        },\n        {\n          width: canvas.width,\n          height: canvas.height,\n          originX: \"left\",\n          originY: \"top\",\n          crossOrigin: \"anonymous\"\n        }\n      )\n    }\n  }\n\n  const clear = () => {\n    canvas.setBackgroundImage(null, () => {\n      canvas.trigger(\"background:modified\")\n      canvas.trigger(\"object:modified\")\n      canvas.discardActiveObject()\n      canvas.requestRenderAll()\n      done()\n    })\n  }\n\n  const toggleBackgroundLock = () => {\n    canvas.lockBackground = !canvas.lockBackground\n    canvas.trigger(\"config:modified\")\n  }\n\n  return (\n    <FileUploader\n      onSuccess={set}\n      actionOptions={{\n        imageDim: [canvas.labelWidth, canvas.labelHeight],\n        transformations: {\n          circle: false,\n          rotate: false,\n          crop: {\n            aspectRatio: canvas.labelWidth / canvas.labelHeight,\n            force: true\n          }\n        }\n      }}\n      customRender={({ onPick }) => (\n        <>\n          <AdminOnly>\n            <div className=\"hidden sm:block\">\n              <div className=\"flex items-center justify-between\">\n                <Label label=\"Background Image\" />\n                {canvas.backgroundImage && (\n                  <a\n                    href={canvas.backgroundImage.src}\n                    download\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-blue-600 px-2\"\n                  >\n                    <FontAwesomeIcon icon={[\"far\", \"download\"]} fixedWidth />\n                  </a>\n                )}\n              </div>\n\n              <div className=\"flex space-x-1\">\n                <IconButton\n                  icon=\"upload\"\n                  size=\"sm\"\n                  className=\"flex-1\"\n                  onClick={onPick}\n                >\n                  {canvas.backgroundImage ? \"Change\" : \"Upload\"}\n                </IconButton>\n                {canvas.backgroundImage && (\n                  <IconButton\n                    icon=\"ban\"\n                    color=\"red\"\n                    size=\"sm\"\n                    className=\"flex-1\"\n                    onClick={clear}\n                  >\n                    Clear\n                  </IconButton>\n                )}\n              </div>\n\n              <div className=\"mt-2 p-1\">\n                <label>\n                  <input\n                    type=\"checkbox\"\n                    checked={canvas.lockBackground}\n                    onClick={toggleBackgroundLock}\n                  />\n                  <span className=\"ml-2\">Lock background</span>\n                </label>\n              </div>\n            </div>\n            <div className=\"sm:hidden\">\n              <MobileControl done={done} title=\"Background image\">\n                <MobileControlList>\n                  {({ className }) => (\n                    <>\n                      <li>\n                        <button\n                          className={classnames(\n                            className,\n                            \"border-b w-full py-3 flex items-center justify-between\"\n                          )}\n                          onClick={onPick}\n                        >\n                          <div>Upload</div>\n                          <FontAwesomeIcon\n                            icon={[\"far\", \"upload\"]}\n                            fixedWidth\n                          />\n                        </button>\n                      </li>\n                      {canvas.backgroundImage && (\n                        <li>\n                          <button\n                            className={classnames(\n                              className,\n                              \"border-b w-full py-3 flex items-center justify-between\"\n                            )}\n                            onClick={clear}\n                          >\n                            <div>Clear</div>\n                            <FontAwesomeIcon\n                              icon={[\"far\", \"trash\"]}\n                              fixedWidth\n                            />\n                          </button>\n                        </li>\n                      )}\n                    </>\n                  )}\n                </MobileControlList>\n              </MobileControl>\n            </div>\n          </AdminOnly>\n          <CustomerOnly>\n            {canvas.backgroundImage && (\n              <div className=\"flex justify-around\">\n                <IconButton\n                  icon=\"arrow-left\"\n                  color=\"red\"\n                  size=\"sm\"\n                  className=\"sm:hidden\"\n                  onClick={done}\n                >\n                  Back\n                </IconButton>\n                <IconButton\n                  icon=\"ban\"\n                  color=\"red\"\n                  size=\"sm\"\n                  className=\"\"\n                  onClick={clear}\n                >\n                  Clear Background\n                </IconButton>\n              </div>\n            )}\n          </CustomerOnly>\n        </>\n      )}\n    />\n  )\n}\n\nexport default CanvasControls\n","import React, { useCallback } from \"react\"\nimport { IconButton } from \"./buttons\"\nimport { useMousetrap } from \"../use-mousetrap\"\n\nconst ObjectControls = ({ selection }) => {\n  const canvas = selection.canvas\n\n  const rotateClockwise = useCallback(() => {\n    selection.rotate(selection.angle + 90)\n    canvas.trigger(\"object:rotated\")\n    canvas.requestRenderAll()\n  }, [selection, canvas])\n\n  const rotateCClockwise = useCallback(() => {\n    selection.rotate(selection.angle - 90)\n    canvas.trigger(\"object:rotated\")\n    canvas.requestRenderAll()\n  }, [selection, canvas])\n\n  const bringForward = useCallback(() => {\n    selection.bringForward()\n    canvas.trigger(\"object:modified\")\n    canvas.requestRenderAll()\n  }, [selection, canvas])\n\n  const sendBackwards = useCallback(() => {\n    selection.sendBackwards()\n    canvas.trigger(\"object:modified\")\n    canvas.requestRenderAll()\n  }, [selection, canvas])\n\n  const clone = useCallback(() => {\n    selection.clone(function(clonedObj) {\n      canvas.discardActiveObject()\n      clonedObj.set({\n        left: clonedObj.left + 20,\n        top: clonedObj.top + 20,\n        evented: true\n      })\n      if (clonedObj.type === \"activeSelection\") {\n        // active selection needs a reference to the canvas.\n        clonedObj.canvas = canvas\n        clonedObj.forEachObject(function(obj) {\n          canvas.add(obj)\n        })\n        // this should solve the unselectability\n        clonedObj.setCoords()\n      } else {\n        canvas.add(clonedObj)\n      }\n      canvas.setActiveObject(clonedObj).requestRenderAll()\n    })\n  }, [canvas, selection])\n\n  const remove = useCallback(() => {\n    if (selection.type === \"activeSelection\") {\n      canvas.remove(...selection.getObjects())\n      canvas.discardActiveObject()\n    } else {\n      canvas.remove(selection)\n    }\n    canvas.requestRenderAll()\n  }, [canvas, selection])\n\n  const moveHorizontal = inc => {\n    selection.set(\"left\", selection.left + inc)\n    canvas.trigger(\"object:modified\")\n    canvas.requestRenderAll()\n  }\n\n  const moveVertical = (inc, e) => {\n    selection.set(\"top\", selection.top + inc)\n    canvas.requestRenderAll()\n    canvas.trigger(\"object:modified\")\n\n    // Prevent page scrolling\n    e.preventDefault()\n  }\n\n  const moveIncrement = Math.ceil(selection.canvas.width * 0.0025)\n\n  const moveUp = e => moveVertical(-1 * moveIncrement, e)\n  const moveDown = e => moveVertical(moveIncrement, e)\n  const moveLeft = e => moveHorizontal(-1 * moveIncrement, e)\n  const moveRight = e => moveHorizontal(moveIncrement, e)\n\n  // Bind up and down to window to prevent movements when other\n  // controls are using keypress events (FontPicker).\n  useMousetrap(\"up\", moveUp, window, [selection, canvas])\n  useMousetrap(\"down\", moveDown, window, [selection, canvas])\n  useMousetrap(\"left\", moveLeft, [selection, canvas])\n  useMousetrap(\"right\", moveRight, [selection, canvas])\n  useMousetrap([\"backspace\", \"del\"], remove, [selection, canvas])\n\n  return (\n    <div className=\"flex justify-center space-x-1\">\n      <IconButton\n        icon={[\"fas\", \"redo\"]}\n        onClick={rotateClockwise}\n        className=\"sm:flex-auto\"\n        title=\"Rotate counter clockwise\"\n        tooltipPosition=\"bottom-right\"\n      />\n      <IconButton\n        icon={[\"fas\", \"undo\"]}\n        onClick={rotateCClockwise}\n        className=\"sm:flex-auto\"\n        title=\"Rotate clockwise\"\n        tooltipPosition=\"bottom-right\"\n      />\n      <IconButton\n        icon={[\"fas\", \"bring-forward\"]}\n        onClick={bringForward}\n        className=\"sm:flex-auto\"\n        title=\"Bring forward\"\n      />\n      <IconButton\n        icon={[\"fas\", \"send-backward\"]}\n        onClick={sendBackwards}\n        className=\"sm:flex-auto\"\n        title=\"Send backward\"\n      />\n      <IconButton\n        icon=\"copy\"\n        onClick={clone}\n        className=\"sm:flex-auto\"\n        title=\"Clone\"\n      />\n      <IconButton\n        icon=\"trash\"\n        color=\"red\"\n        onClick={remove}\n        className=\"sm:flex-auto\"\n        title=\"Remove\"\n        tooltipPosition=\"bottom-left\"\n      />\n    </div>\n  )\n}\n\nexport const BackToLayers = ({ selection }) => {\n  const clearSelection = () => {\n    selection.canvas.requestRenderAll()\n    selection.canvas.discardActiveObject()\n  }\n\n  return (\n    <div className=\"p-1\">\n      <IconButton\n        onClick={clearSelection}\n        icon=\"arrow-left\"\n        size=\"sm\"\n        className=\"w-full text-center\"\n      >\n        Back to layers\n      </IconButton>\n    </div>\n  )\n}\n\nexport default ObjectControls\n","import WebFont from \"webfontloader\"\n\nexport const webFonts = [\n  \"Abril Fatface\",\n  \"Alegreya SC\",\n  \"Alex Brush\",\n  \"Allura\",\n  \"Amatic SC\",\n  \"Anaheim\",\n  \"Arbutus Slab\",\n  \"Asul\",\n  \"Bad Script\",\n  \"Bad Script Regular\",\n  \"Berkshire Swash\",\n  \"Bevan\",\n  \"BioRhyme Expanded\",\n  \"Buenard\",\n  \"Calligraffitti\",\n  \"Cinzel\",\n  \"Codystar\",\n  \"Cormorant Garamond\",\n  \"Cutive Mono\",\n  \"Damion\",\n  \"Diplomata SC\",\n  \"Engagement\",\n  \"Exo\",\n  \"Finger Paint\",\n  \"Freckle Face\",\n  \"Gloria Hallelujah\",\n  \"Graduate\",\n  \"Great Vibes\",\n  \"Griffy\",\n  \"Gruppo\",\n  \"Headland One\",\n  \"Homemade Apple\",\n  \"IM Fell DW Pica SC\",\n  \"Italianno\",\n  \"Jim Nightshade\",\n  \"Julius Sans One\",\n  \"Just Another Hand\",\n  \"Knewave\",\n  \"Lato\",\n  \"Limelight\",\n  \"Lobster\",\n  \"Londrina Shadow\",\n  \"Macondo Swash Caps\",\n  \"Molle\",\n  \"Monsieur La Doulaise\",\n  \"Montserrat Alternates\",\n  \"Montserrat\",\n  \"Mr De Haviland\",\n  \"Niconne\",\n  \"Nunito\",\n  \"Old Standard TT\",\n  \"Oswald\",\n  \"Pacifico\",\n  \"Paytone One\",\n  \"Permanent Marker\",\n  \"Petit Formal Script\",\n  \"Piedra\",\n  \"Pirata One\",\n  \"Plaster\",\n  \"Quicksand\",\n  \"Rakkas\",\n  \"Raleway\",\n  \"Reem Kufi\",\n  \"Roboto Slab\",\n  \"Rock Salt\",\n  \"Rouge Script\",\n  \"Rubik Mono One\",\n  \"Ruge Boogie\",\n  \"Rye\",\n  \"Sacramento\",\n  \"Six Caps\",\n  \"Stalemate\",\n  \"Tangerine\",\n  \"Underdog\",\n  \"Yanone Kaffeesatz\",\n  \"Yesteryear\"\n]\n\nexport const systemFonts = [\"Arial\", \"Helvetica\", \"Times New Roman\"]\n\nexport const fonts = [...webFonts, ...systemFonts]\n\nexport const loadFonts = () =>\n  WebFont.load({\n    classes: false,\n    events: false,\n    google: { families: webFonts }\n  })\n","import React, { useCallback } from \"react\"\nimport FontFaceObserver from \"fontfaceobserver\"\nimport classnames from \"classnames\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport { MobileControl, MobileControlSelect } from \"./controls-components\"\nimport { useSelectionProperty } from \"./fabric-react\"\nimport { useSelect } from \"downshift\"\nimport { fonts, webFonts } from \"./fonts\"\n\nconst useFontFamily = selection => {\n  const fontFamily = useSelectionProperty(selection, \"fontFamily\")\n\n  const setFontFamily = useCallback(\n    family => {\n      if (selection.type === \"activeSelection\") {\n        selection.forEachObject(o => {\n          o.set(\"fontFamily\", family)\n          o.trigger(\"modified\")\n        })\n      } else {\n        selection.set(\"fontFamily\", family)\n        selection.trigger(\"modified\")\n      }\n\n      // Wait for web fonts to be loaded before\n      // rendering the canvas.\n      if (webFonts.includes(family)) {\n        var o = new FontFaceObserver(family)\n        o.load().then(() => selection.canvas.requestRenderAll())\n      } else {\n        selection.canvas.requestRenderAll()\n      }\n    },\n    [selection]\n  )\n\n  return [fontFamily, setFontFamily]\n}\n\nconst FontPicker = ({ selection }) => {\n  const [fontFamily, setFontFamily] = useFontFamily(selection)\n  const handleSelectedItemChange = useCallback(\n    ({ selectedItem }) => setFontFamily(selectedItem),\n    [setFontFamily]\n  )\n\n  const {\n    isOpen,\n    selectedItem,\n    getToggleButtonProps,\n    getMenuProps,\n    highlightedIndex,\n    getItemProps\n  } = useSelect({\n    items: fonts,\n    initialSelectedItem: fontFamily,\n    onSelectedItemChange: handleSelectedItemChange\n  })\n\n  return (\n    <div>\n      <button\n        {...getToggleButtonProps()}\n        className={classnames(\n          \"w-full p-2 rounded text-left flex items-center justify-between surface\",\n          { \"text-blue-700 bg-blue-300\": isOpen }\n        )}\n        style={{\n          fontFamily: selectedItem\n        }}\n        title=\"Font\"\n      >\n        <span className=\"truncate\">{selectedItem}</span>\n        <FontAwesomeIcon\n          icon={[\"fas\", \"caret-down\"]}\n          className=\"text-gray-600\"\n        />\n      </button>\n      <div className=\"absolute z-50\">\n        <div\n          {...getMenuProps({\n            // Prevent events from propagating, as this will cause navigation\n            // of the select menu to cause objects on the canvas to move.\n            onKeyDown: e => e.nativeEvent.stopPropagation()\n          })}\n          className={classnames(\n            \"m-1 h-64 w-56 overflow-y-auto bg-white text-gray-700 shadow-2xl rounded\",\n            { hidden: !isOpen }\n          )}\n        >\n          {fonts.sort().map((family, index) => {\n            const highlighted = highlightedIndex === index\n            const selected = selectedItem === family\n\n            return (\n              <button\n                key={`${family}${index}`}\n                {...getItemProps({\n                  item: family,\n                  index\n                })}\n                className={classnames(\"w-full block p-2 text-left surface\", {\n                  \"surface-focus\": !selected && highlighted,\n                  \"bg-blue-300\": selected\n                })}\n                style={{ fontFamily: family }}\n              >\n                {family}\n              </button>\n            )\n          })}\n        </div>\n      </div>\n    </div>\n  )\n}\n\nexport const MobileFontPicker = ({ selection, done }) => {\n  const [fontFamily, setFontFamily] = useFontFamily(selection)\n  return (\n    <MobileControl done={done} title=\"Font\">\n      <MobileControlSelect\n        options={fonts.sort()}\n        onChange={setFontFamily}\n        selected={fontFamily}\n        getOptionStyle={({ option }) => ({ fontFamily: option })}\n      />\n    </MobileControl>\n  )\n}\n\nexport default FontPicker\n","import React from \"react\"\nimport { useCombobox } from \"downshift\"\nimport classnames from \"classnames\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport { MobileControl, MobileControlSelect } from \"./controls-components\"\nimport { IconButton } from \"./buttons\"\n\nconst getStateReducer = ({ min }) => (state, actionAndChanges) => {\n  switch (actionAndChanges.type) {\n    // Reset to original value\n    case useCombobox.stateChangeTypes.InputBlur:\n      return {\n        ...actionAndChanges.changes,\n        ...(state.highlightedIndex < 0 && {\n          isOpen: false,\n          inputValue: actionAndChanges.props.initialInputValue\n        })\n      }\n    // If\n    case useCombobox.stateChangeTypes.InputKeyDownEnter: {\n      const parsed = parseInt(state.inputValue)\n\n      return {\n        ...actionAndChanges.changes,\n        ...(state.highlightedIndex < 0 && {\n          isOpen: false,\n          inputValue:\n            isNaN(parsed) && parsed >= min\n              ? actionAndChanges.props.initialInputValue\n              : parsed.toString()\n        })\n      }\n    }\n    default:\n      return actionAndChanges.changes\n  }\n}\n\nconst NumberSelect = ({\n  initialValue,\n  onChange,\n  inputs,\n  min = 0,\n  label = null,\n  tooltipPosition = \"bottom-left\"\n}) => {\n  const {\n    isOpen,\n    getToggleButtonProps,\n    getMenuProps,\n    getInputProps,\n    getComboboxProps,\n    highlightedIndex,\n    selectedItem,\n    getItemProps\n  } = useCombobox({\n    items: inputs,\n    initialInputValue: initialValue ? initialValue.toString() : \"\",\n    // Ideally we'd be directly looking for input enter and select item events\n    // and filtering by type, but for some reason the property isn't present\n    // despite what the docs says. isOpen accomplishes the same thing albeit in\n    // a less explicity way.\n    onIsOpenChange: ({ inputValue, isOpen }) => {\n      if (!isOpen) {\n        // The onIsOpenChange callback isn't called asynchronously as its\n        // really the onSelectedItemChange callback that is used to handle\n        // input changes, but this hack prevents the react error and works.\n        // Unsure why the \"open numeric field but with preset selections\" isn't\n        // a more common downshift usecase.\n        setTimeout(() => onChange(parseInt(inputValue)), 0)\n      }\n    },\n    stateReducer: getStateReducer({ min })\n  })\n\n  return (\n    <>\n      <div\n        className={classnames(\"flex items-center py-1 pl-1 surface\", {\n          \"bg-blue-300 text-blue-700\": isOpen\n        })}\n        {...getComboboxProps()}\n      >\n        <div className=\"flex-1\">\n          <input className=\"w-full py-1 px-3\" {...getInputProps()} />\n        </div>\n        <div className=\"flex-none\">\n          <button\n            className=\"p-1\"\n            {...getToggleButtonProps()}\n            {...(label && {\n              role: \"tooltip\",\n              \"aria-label\": label,\n              \"data-microtip-position\": tooltipPosition\n            })}\n          >\n            <FontAwesomeIcon\n              icon={[\"fas\", \"caret-down\"]}\n              className=\"text-gray-600\"\n            />\n          </button>\n        </div>\n      </div>\n      <ul\n        className={classnames(\n          \"absolute z-50 mt-1 h-64 w-48 overflow-y-auto bg-white shadow-2xl rounded-lg\",\n          { hidden: !isOpen }\n        )}\n        {...getMenuProps()}\n      >\n        {isOpen &&\n          inputs.map((item, index) => {\n            const highlighted = highlightedIndex === index\n            const selected = selectedItem === item\n\n            return (\n              <li\n                key={`${item}${index}`}\n                className={classnames(\"p-1\", {\n                  \"surface-focus\": !selected && highlighted,\n                  \"bg-blue-300\": selected\n                })}\n                {...getItemProps({ item, index })}\n              >\n                {item}\n              </li>\n            )\n          })}\n      </ul>\n    </>\n  )\n}\n\nexport const MobileNumberSelect = ({\n  done,\n  value,\n  options,\n  onChange,\n  title,\n  min = 0,\n  step = 1\n}) => {\n  const decrement = () => onChange(Math.max(min, value - step))\n  const increment = () => onChange(value + step)\n\n  return (\n    <MobileControl\n      done={done}\n      title={title}\n      renderTitleBar={() => (\n        <div className=\"flex items-center justify-center\">\n          <IconButton icon=\"chevron-down\" onClick={decrement} />\n          <div className=\"px-2\">{value}</div>\n          <IconButton icon=\"chevron-up\" onClick={increment} />\n        </div>\n      )}\n    >\n      <MobileControlSelect\n        options={options}\n        selected={value}\n        onChange={onChange}\n      />\n    </MobileControl>\n  )\n}\n\nexport default NumberSelect\n","import React from \"react\"\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\"\nimport classnames from \"classnames\"\nimport { SelectButton } from \"./buttons\"\nimport { useSelectionProperty } from \"./fabric-react\"\nimport { useSelect } from \"downshift\"\n\nconst alignments = [\"left\", \"center\", \"right\"]\n\nconst TextAlignControl = ({ selection, apply }) => {\n  const textAlign = useSelectionProperty(selection, \"textAlign\")\n  const setTextAlign = align => apply(object => object.set(\"textAlign\", align))\n\n  const {\n    isOpen,\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    highlightedIndex,\n    getItemProps,\n    selectedItem\n  } = useSelect({\n    initialSelectedItem: textAlign,\n    items: alignments,\n    onSelectedItemChange: c => setTextAlign(c.selectedItem)\n  })\n\n  return (\n    <div className=\"relative sm:static\">\n      <label {...getLabelProps()} className=\"hidden\">\n        Select a text alignment\n      </label>\n      <SelectButton icon={`align-${textAlign}`} {...getToggleButtonProps()} />\n      <div className=\"z-10 absolute bottom-0 mb-8 bg-white rounded-lg shadow-xl overflow-hidden sm:bottom-auto sm:mb-0\">\n        <ul\n          {...getMenuProps({ onKeyDown: e => e.nativeEvent.stopPropagation() })}\n        >\n          {isOpen &&\n            alignments.map((item, index) => {\n              const highlighted = highlightedIndex === index\n              const selected = selectedItem === item\n              return (\n                <li\n                  key={index}\n                  className={classnames(\"surface p-4 cursor-pointer\", {\n                    \"surface-focus\": !selected && highlighted,\n                    \"bg-blue-300\": selected\n                  })}\n                  {...getItemProps({\n                    index,\n                    item\n                  })}\n                >\n                  <FontAwesomeIcon\n                    icon={[\"far\", `align-${item}`]}\n                    size=\"lg\"\n                    fixedWidth\n                  />\n                </li>\n              )\n            })}\n        </ul>\n      </div>\n    </div>\n  )\n}\n\nexport default TextAlignControl\n","import React from \"react\"\nimport classnames from \"classnames\"\nimport { SelectButton } from \"./buttons\"\nimport { useSelectionProperty } from \"./fabric-react\"\nimport { useSelect } from \"downshift\"\n\nconst spacings = {\n  normal: 0,\n  wide: 25,\n  wider: 50,\n  widest: 100\n}\n\nconst items = Object.keys(spacings)\n\nconst getSpacing = item => {\n  return spacings[item] || 0\n}\n\nconst getItem = spacing => {\n  switch (spacing) {\n    case null:\n    case spacings[\"normal\"]:\n      return \"normal\"\n    case spacings[\"wide\"]:\n      return \"wide\"\n    case spacings[\"wider\"]:\n      return \"wider\"\n    case spacings[\"widest\"]:\n      return \"widest\"\n    default:\n      return null\n  }\n}\n\nconst LetterSpacingControl = ({ selection, apply }) => {\n  const charSpacing = useSelectionProperty(selection, \"charSpacing\")\n  const setCharSpacing = spacing =>\n    apply(object => object.set(\"charSpacing\", spacing))\n\n  const {\n    isOpen,\n    getToggleButtonProps,\n    getLabelProps,\n    getMenuProps,\n    highlightedIndex,\n    getItemProps,\n    selectedItem\n  } = useSelect({\n    initialSelectedItem: getItem(charSpacing),\n    items,\n    onSelectedItemChange: c => {\n      const spacing = getSpacing(c.selectedItem)\n      setCharSpacing(spacing)\n    }\n  })\n\n  return (\n    <div className=\"relative sm:static\">\n      <label {...getLabelProps()} className=\"hidden\">\n        Select letter spacing size:\n      </label>\n      <SelectButton icon=\"kerning\" {...getToggleButtonProps()} />\n      <div className=\"z-10 absolute bottom-0 mb-8 bg-white rounded-lg shadow-xl overflow-hidden sm:bottom-auto sm:mb-0\">\n        <ul\n          {...getMenuProps({ onKeyDown: e => e.nativeEvent.stopPropagation() })}\n        >\n          {isOpen &&\n            items.map((item, index) => {\n              const highlighted = highlightedIndex === index\n              const selected = selectedItem === item\n\n              return (\n                <li\n                  key={index}\n                  className={classnames(\"surface p-4 cursor-pointer\", {\n                    \"surface-focus\": !selected && highlighted,\n                    \"bg-blue-300\": selected\n                  })}\n                  {...getItemProps({\n                    index,\n                    item\n                  })}\n                >\n                  {item}\n                </li>\n              )\n            })}\n        </ul>\n      </div>\n    </div>\n  )\n}\n\nexport default LetterSpacingControl\n","import React from \"react\"\nimport ColorPicker from \"./color-picker\"\nimport { useSelectionProperty } from \"./fabric-react\"\nimport { Label } from \"./controls-components\"\n\nconst TextShadowControls = ({ selection, apply }) => {\n  const value = useSelectionProperty(selection, \"shadow\")\n  const fontSize = useSelectionProperty(selection, \"fontSize\")\n\n  const blur = 3 + Math.floor(fontSize * 0.06)\n  const offsetX = 1 + Math.floor(fontSize * 0.03)\n  const offsetY = 1 + Math.floor(fontSize * 0.03)\n\n  const setShadow = (color = \"rgba(0,0,0,0.2)\") =>\n    apply(object => {\n      object.set(\"shadow\", {\n        color,\n        offsetX,\n        offsetY,\n        blur\n      })\n    })\n\n  const shadow = useSelectionProperty(selection, \"shadow\")\n  const setBlur = blur => {\n    blur = parseInt(blur)\n    apply(o => {\n      o.set(\"shadow\", {\n        ...(o.shadow || o.defaultShadow()),\n        blur\n      })\n    })\n  }\n\n  const setOffsetX = offsetX => {\n    offsetX = parseInt(offsetX)\n    apply(o => {\n      o.set(\"shadow\", {\n        ...(o.shadow || o.defaultShadow()),\n        offsetX\n      })\n    })\n  }\n\n  const setOffsetY = offsetY => {\n    offsetY = parseInt(offsetY)\n    apply(o => {\n      o.set(\"shadow\", {\n        ...(o.shadow || o.defaultShadow()),\n        offsetY\n      })\n    })\n  }\n\n  const clear = () => apply(object => object.set(\"shadow\", null))\n\n  return (\n    <>\n      <Label label=\"Shadow Color\" />\n      <ColorPicker\n        value={value && value.color}\n        onClear={clear}\n        onChange={setShadow}\n      />\n      <div className=\"flex border-t\">\n        <div className=\"p-1\">\n          <Label label=\"Blur\" />\n          <input\n            onChange={e => setBlur(parseInt(e.target.value))}\n            value={shadow !== null ? shadow.blur : 0}\n            type=\"number\"\n            className=\"w-full py-1 px-3\"\n          />\n        </div>\n        <div className=\"p-1 border-l border-r\">\n          <Label label=\"Offset X\" />\n          <input\n            onChange={e => setOffsetX(e.target.value)}\n            value={shadow !== null ? shadow.offsetX : 0}\n            type=\"number\"\n            className=\"w-full py-1 px-3\"\n          />\n        </div>\n        <div className=\"p-1\">\n          <Label label=\"Offset Y\" />\n          <input\n            onChange={e => setOffsetY(e.target.value)}\n            value={shadow !== null ? shadow.offsetY : 0}\n            type=\"number\"\n            className=\"w-full py-1 px-3\"\n          />\n        </div>\n      </div>\n    </>\n  )\n}\n\nexport default TextShadowControls\n","import React, { useEffect, useRef, useState } from \"react\"\nimport { useMousetrap } from \"../use-mousetrap\"\nimport { IconButton, SelectButton } from \"./buttons\"\nimport { useSelectionProperty } from \"./fabric-react\"\nimport {\n  AdminOnly,\n  Label,\n  LabelOnly,\n  EngravingOnly\n} from \"./controls-components\"\nimport ObjectControls, { BackToLayers } from \"./object-controls\"\nimport FontPicker, { MobileFontPicker } from \"./font-picker\"\nimport ColorPicker, { MobileColorPicker } from \"./color-picker\"\nimport NumberSelect, { MobileNumberSelect } from \"./number-select\"\nimport AlignControl from \"./text-align\"\nimport LetterSpacingControl from \"./letter-spacing\"\nimport TextShadowControls from \"./text-shadow-controls\"\n\nconst fontSizeOptions = [50, 75, 100, 125, 175, 225, 300, 400, 500]\n\nconst TextControls = ({ selection, apply }) => {\n  const text = useSelectionProperty(selection, \"text\", [\"changed\", \"modified\"])\n  const setText = text => apply(object => object.set(\"text\", text))\n\n  const textAlign = useSelectionProperty(selection, \"textAlign\")\n  const setTextAlign = align => apply(object => object.set(\"textAlign\", align))\n\n  const fontSize = useSelectionProperty(selection, \"fontSize\")\n  const setFontSize = size => apply(o => o.set(\"fontSize\", Math.max(size, 30)))\n\n  const charSpacing = useSelectionProperty(selection, \"charSpacing\")\n  const setCharSpacing = spacing => apply(o => o.set(\"charSpacing\", spacing))\n\n  const isItalic = useSelectionProperty(selection, \"fontStyle\") === \"italic\"\n  const toggleItalic = () => {\n    const fontStyle = isItalic ? \"\" : \"italic\"\n    apply(o => o.set(\"fontStyle\", fontStyle))\n  }\n\n  const isBold = useSelectionProperty(selection, \"fontWeight\") === 900\n  const toggleBold = () => {\n    const fontWeight = isBold ? 400 : 900\n    apply(o => o.set(\"fontWeight\", fontWeight))\n  }\n\n  const color = useSelectionProperty(selection, \"fill\")\n  const setColor = color => apply(object => object.set(\"fill\", color))\n\n  const isShadow = !!useSelectionProperty(selection, \"shadow\")\n  const toggleShadow = () =>\n    apply(o => {\n      o.set(\"shadow\", o.shadow === null ? { ...o.defaultShadow() } : null)\n    })\n\n  const controlProps = {\n    text,\n    apply,\n    setText,\n    selection,\n    color,\n    setColor,\n    fontSize,\n    setFontSize,\n    textAlign,\n    setTextAlign,\n    isItalic,\n    toggleItalic,\n    isBold,\n    toggleBold,\n    isShadow,\n    toggleShadow,\n    charSpacing,\n    setCharSpacing\n  }\n\n  // Bind hotkeys\n  useMousetrap([\"ctrl+b\", \"command+b\"], toggleBold)\n  useMousetrap([\"ctrl+i\", \"command+i\"], toggleItalic)\n\n  return (\n    <>\n      <DesktopControls {...controlProps} />\n      <MobileControls {...controlProps} />\n    </>\n  )\n}\n\nconst DesktopControls = ({\n  apply,\n  selection,\n  color,\n  setColor,\n  fontSize,\n  setFontSize,\n  isItalic,\n  toggleItalic,\n  isBold,\n  toggleBold,\n  isShadow,\n  toggleShadow,\n  charSpacing,\n  setCharSpacing\n}) => (\n  <div className=\"hidden sm:block divide-y\">\n    <BackToLayers selection={selection} />\n    <div className=\"p-1\">\n      <ObjectControls selection={selection} />\n    </div>\n    <div className=\"p-1\">\n      <div className=\"flex\">\n        <div className=\"pr-1\" style={{ width: \"66%\" }}>\n          <FontPicker selection={selection} />\n        </div>\n        <div style={{ width: \"34%\" }}>\n          <NumberSelect\n            inputs={fontSizeOptions}\n            initialValue={fontSize}\n            onChange={setFontSize}\n            min={40}\n            title=\"Font Size\"\n          />\n        </div>\n      </div>\n    </div>\n    <div className=\"p-1 flex justify-between space-x-1\">\n      <AlignControl selection={selection} apply={apply} />\n      <IconButton\n        icon=\"italic\"\n        color={isItalic && \"blue\"}\n        onClick={toggleItalic}\n        title=\"Italic\"\n        label=\"Italic\"\n      />\n      <IconButton\n        icon=\"bold\"\n        color={isBold && \"blue\"}\n        onClick={toggleBold}\n        title=\"Bold\"\n      />\n      <LetterSpacingControl selection={selection} apply={apply} />\n      <LabelOnly>\n        <IconButton\n          icon=\"eclipse\"\n          active={isShadow}\n          onClick={toggleShadow}\n          title=\"Text shadow\"\n        />\n      </LabelOnly>\n    </div>\n    <LabelOnly>\n      <div className=\"p-1\">\n        <ColorPicker value={color} onChange={setColor} />\n      </div>\n    </LabelOnly>\n    <AdminOnly>\n      <div className=\"p-1\">\n        <EngravingOnly>\n          <div className=\"p-1\">\n            <ColorPicker value={color} onChange={setColor} />\n          </div>\n        </EngravingOnly>\n        <Label label=\"Character Spacing\" />\n        <input\n          onChange={e => setCharSpacing(e.target.value)}\n          value={charSpacing || 0}\n          type=\"number\"\n          className=\"w-full py-1 px-3\"\n        />\n\n        <div className=\"p-1\">\n          <TextShadowControls selection={selection} apply={apply} />\n        </div>\n      </div>\n    </AdminOnly>\n  </div>\n)\n\nconst controlKeys = {\n  font: \"Font\",\n  color: \"Text Color\",\n  size: \"Font Size\"\n}\n\nconst MobileControls = ({\n  apply,\n  selection,\n  text,\n  setText,\n  color,\n  setColor,\n  fontSize,\n  setFontSize,\n  isItalic,\n  toggleItalic,\n  isBold,\n  toggleBold,\n  isShadow,\n  toggleShadow\n}) => {\n  const [control, setControl] = useState(null)\n\n  if (!control) {\n    return (\n      <div className=\"sm:hidden divide-y\">\n        {selection.type !== \"activeSelection\" && (\n          <TextControl value={text} onChange={setText} />\n        )}\n        <div className=\"p-1 flex items-center space-x-px\">\n          <IconButton\n            onClick={() => setControl(controlKeys.font)}\n            icon=\"font\"\n            description=\"Font\"\n          />\n          <SelectButton\n            onClick={() => setControl(controlKeys.size)}\n            textStyle=\"plain\"\n          >\n            {fontSize}\n          </SelectButton>\n          <LabelOnly>\n            <IconButton\n              onClick={() => setControl(controlKeys.color)}\n              icon=\"font\"\n              iconProps={{ size: \"sm\" }}\n              className=\"flex items-center flex-col\"\n            >\n              <div\n                className=\"w-full h-1-h mt-1 border\"\n                style={{ backgroundColor: color }}\n              />\n            </IconButton>\n          </LabelOnly>\n          <AlignControl selection={selection} apply={apply} />\n          <LetterSpacingControl selection={selection} apply={apply} />\n          <IconButton\n            icon=\"italic\"\n            active={isItalic}\n            onClick={toggleItalic}\n            className=\"flex-auto \"\n            description=\"Italic\"\n          />\n          <IconButton\n            icon=\"bold\"\n            active={isBold}\n            onClick={toggleBold}\n            className=\"flex-auto mx-1\"\n            description=\"Bold\"\n          />\n          <LabelOnly>\n            <IconButton\n              icon=\"eclipse\"\n              active={isShadow}\n              className=\"flex-auto ml-1\"\n              onClick={toggleShadow}\n            />\n          </LabelOnly>\n        </div>\n        <div className=\"p-1\">\n          <ObjectControls selection={selection} />\n        </div>\n        <BackToLayers selection={selection} />\n      </div>\n    )\n  }\n\n  const done = () => setControl(null)\n\n  switch (control) {\n    case controlKeys.font:\n      return <MobileFontPicker done={done} selection={selection} />\n    case controlKeys.color:\n      return (\n        <MobileColorPicker\n          done={done}\n          title=\"Text color\"\n          value={color}\n          onChange={setColor}\n        />\n      )\n    case controlKeys.size:\n      return (\n        <MobileNumberSelect\n          done={done}\n          title=\"Font size\"\n          value={fontSize}\n          min={40}\n          step={5}\n          onChange={setFontSize}\n          options={fontSizeOptions}\n        />\n      )\n    default:\n      throw new Error(\"Unmapped text control value set\")\n  }\n}\n\nconst TextControl = ({ value, onChange }) => {\n  /*\n   * Listen to change events so that we know when the text\n   * has been changed via canvas interaction.\n   */\n  const [isActive, setIsActive] = useState(false)\n  const ref = useRef()\n\n  const handleChange = e => onChange(e.target.value)\n  const handleEnter = e => {\n    if (e.key === \"Enter\" || e.keycode === 13) {\n      e.target.blur()\n    }\n  }\n\n  const blur = () => {\n    ref.current.blur()\n  }\n\n  // useEffect(() => ref.current && ref.current.focus(), [])\n\n  return (\n    <div className=\"p-1 flex divide-x\">\n      <input\n        type=\"text\"\n        ref={ref}\n        value={value}\n        onChange={handleChange}\n        onKeyDown={handleEnter}\n        onFocus={() => setIsActive(true)}\n        onBlur={() => setIsActive(false)}\n        className=\"p-2 flex-auto outline-none\"\n      />\n      <IconButton\n        icon=\"check\"\n        color=\"green\"\n        onClick={blur}\n        className={isActive ? \"\" : \"invisible\"}\n      />\n    </div>\n  )\n}\n\nexport default TextControls\n","import React, { useCallback } from \"react\"\nimport { Range, getTrackBackground } from \"react-range\"\n\nconst Slider = ({\n  values,\n  min,\n  max,\n  onChange,\n  step = 0.025,\n  rangeProps = {}\n}) => {\n  const handleChange = useCallback(v => onChange(v[0]), [onChange])\n\n  // Round values to the nearest step\n  const roundedValues = values.map(v => Math.ceil(v / step) * step)\n  const roundedMax = Math.ceil(max / step) * step\n\n  return (\n    <div className=\"m-4\">\n      <Range\n        values={roundedValues}\n        step={step}\n        min={min}\n        max={roundedMax}\n        onChange={handleChange}\n        renderTrack={({ props, children }) => (\n          <div\n            {...props}\n            style={{\n              ...props.style,\n              background: getTrackBackground({\n                values: roundedValues,\n                colors: [\"#548BF4\", \"#bee3f8\"],\n                min,\n                max\n              })\n            }}\n            className=\"w-full h-1 rounded-lg bg-blue-200\"\n          >\n            {children}\n          </div>\n        )}\n        renderThumb={({ props }) => (\n          <div\n            {...props}\n            className=\"outline-none shadow hover:shadow-lg w-6 h-6 rounded-full border-full bg-blue-600\"\n          />\n        )}\n        {...rangeProps}\n      />\n    </div>\n  )\n}\n\nexport default Slider\n","import React from \"react\"\nimport ObjectControls, { BackToLayers } from \"./object-controls\"\nimport FileUploader from \"./file-uploader\"\nimport { useCanvas, useSelectionProperty } from \"./fabric-react\"\nimport { IconButton } from \"./buttons\"\nimport Slider from \"./slider\"\nimport { AdminOnly } from \"./controls-components\"\n\nconst ImageControls = ({\n  selection,\n  apply,\n  cropImage,\n  editFramedImage,\n  medium\n}) => {\n  return (\n    <div className=\"flex flex-col sm:flex-col-reverse divide-y\">\n      {selection.type === \"activeSelection\" ? null : (\n        <>\n          <div className=\"p-1\">\n            <ImageControl\n              medium={medium}\n              object={selection}\n              cropImage={cropImage}\n              editFramedImage={editFramedImage}\n              selection={selection}\n            />\n          </div>\n          <div className=\"p-1\">\n            <ScaleControl selection={selection} apply={apply} />\n          </div>\n        </>\n      )}\n      <div className=\"p-1\">\n        <ObjectControls selection={selection} />\n      </div>\n      <BackToLayers selection={selection} />\n    </div>\n  )\n}\n\nconst ScaleControl = ({ selection, apply }) => {\n  const scaleX = useSelectionProperty(selection, \"scaleX\")\n\n  const scaleImage = scale => {\n    apply(object => {\n      object.set(\"scaleX\", scale)\n      object.set(\"scaleY\", scale)\n    })\n  }\n\n  const canvas = useCanvas()\n  const height = selection.height\n  const width = selection.width\n\n  const maxHeightScale = canvas.height / height\n  const maxWidthScale = canvas.width / width\n\n  var maxScale = Math.max(maxHeightScale, maxWidthScale) * 1.33\n  maxScale = Math.max(maxScale, scaleX)\n\n  return (\n    <Slider\n      values={[scaleX]}\n      onChange={scaleImage}\n      max={maxScale}\n      min={0.05}\n      step={0.01}\n    />\n  )\n}\n\nconst ImageControl = ({ object, cropImage, editFramedImage, selection }) => {\n  const src = useSelectionProperty(object, o => o.getSrc())\n\n  const replace = src => {\n    const width = object.getScaledWidth()\n    let url = src\n    // Potential improvement: grab some information about the initial\n    // image size and origin and apply some transforms to make the\n    // new image fit better to the original size.\n    object.setSrc(\n      url,\n      () => {\n        object\n          .set({\n            cropX: null,\n            cropY: null\n          })\n          .scaleToWidth(width)\n\n        object.trigger(\"modified\")\n        object.canvas.trigger(\"object:modified\")\n        object.canvas.requestRenderAll()\n      },\n      {\n        crossOrigin: true\n      }\n    )\n  }\n\n  const onSuccess = res => {\n    if (res.filesUploaded.length > 0) {\n      replace(res.filesUploaded[0].url)\n    }\n  }\n\n  const crop = () => {\n    cropImage(object) // set crop target\n  }\n\n  let isCroppable = !object.clipPath\n  let isFramed = object.isFrame\n\n  return (\n    <FileUploader\n      key={src}\n      onSuccess={onSuccess}\n      actionOptions={{\n        disableTransformer: true,\n        maxSize: 10 * 1024 * 1024, // 10 mb\n        startUploadingWhenMaxFilesReached: true,\n        imageMax: [object.canvas.width, object.canvas.height]\n      }}\n      customRender={({ onPick }) => (\n        <div className=\"flex items-center\">\n          <div className=\"hidden sm:block flex-none pr-1-h\">\n            <button\n              className=\"border-gray-600 hover:border-blue-600\"\n              onClick={onPick}\n            >\n              <Image src={src} />\n            </button>\n          </div>\n          <div className=\"flex-auto flex sm:flex-col sm:divide-y\">\n            <div className=\"flex-1 px-1 sm:pb-1\">\n              <IconButton\n                icon=\"upload\"\n                className=\"w-full justify-center\"\n                onClick={onPick}\n              >\n                Replace\n              </IconButton>\n            </div>\n            {isCroppable && (\n              <div className=\"flex-1 px-1 sm:pt-1\">\n                <IconButton\n                  icon=\"crop\"\n                  className=\"w-full justify-center\"\n                  onClick={crop}\n                >\n                  Crop\n                </IconButton>\n              </div>\n            )}\n            {isFramed && (\n              <AdminOnly>\n                <div className=\"flex-1 px-1 sm:pt-1\">\n                  <IconButton\n                    icon=\"crop\"\n                    className=\"w-full justify-center\"\n                    onClick={() => editFramedImage(selection)}\n                  >\n                    Edit Clipping\n                  </IconButton>\n                </div>\n              </AdminOnly>\n            )}\n          </div>\n        </div>\n      )}\n    />\n  )\n}\n\nconst Image = ({ src }) => (\n  <div\n    className=\"rounded-full border-solid border-2 bg-center bg-cover mr-2 w-20 h-20\"\n    style={{\n      backgroundImage: `url(${src})`,\n      borderColor: \"inherit\"\n    }}\n  />\n)\n\nexport default ImageControls\n","import React from \"react\"\nimport { useSelection } from \"./fabric-react\"\nimport CanvasControls from \"./canvas-controls\"\nimport TextControls from \"./text-controls\"\nimport ImageControls from \"./image-controls\"\nimport ObjectControls from \"./object-controls\"\n\nconst Controls = ({ cropImage, editFramedImage, medium }) => {\n  const { selection, getProperty, apply } = useSelection()\n\n  if (!selection) {\n    return <CanvasControls />\n  }\n\n  const selectionType = getProperty(\"type\")\n  return (\n    <>\n      {(() => {\n        switch (selectionType) {\n          case \"textbox\":\n            return (\n              <TextControls\n                selection={selection}\n                getProperty={getProperty}\n                apply={apply}\n              />\n            )\n          case \"image\":\n            return (\n              <ImageControls\n                medium={medium}\n                cropImage={cropImage}\n                editFramedImage={editFramedImage}\n                selection={selection}\n                apply={apply}\n              />\n            )\n          default:\n            return (\n              <div className=\"p-1-h\">\n                <ObjectControls selection={selection} />\n              </div>\n            )\n        }\n      })()}\n    </>\n  )\n}\n\nexport default Controls\n","import { useEffect, useRef, useState } from \"react\"\n\nexport const useDropdown = () => {\n  const [isOpen, setIsOpen] = useState(false)\n\n  const toggleRef = useRef(null)\n  const dropdownRef = useRef(null)\n\n  useEffect(() => {\n    const handleEveryClick = event => {\n      if (!isOpen || dropdownRef.current.contains(event.target)) {\n        return\n      }\n\n      setIsOpen(false)\n    }\n\n    document.addEventListener(\"click\", handleEveryClick)\n    return () => document.removeEventListener(\"click\", handleEveryClick)\n  }, [isOpen, dropdownRef])\n\n  const toggle = () => setIsOpen(!isOpen)\n  const handleKeyDown = e => {\n    if (e.key === \"Enter\") {\n      e.preventDefault()\n      setIsOpen(true)\n    }\n  }\n\n  const toggleProps = {\n    onKeyDown: handleKeyDown,\n    onClick: toggle,\n    ref: toggleRef\n  }\n\n  const dropdownProps = {\n    ref: dropdownRef\n  }\n\n  return {\n    toggleProps,\n    dropdownProps,\n    isOpen\n  }\n}\n","import React from \"react\"\nimport cx from \"classnames\"\nimport { useDropdown } from \"../hooks/use-dropdown\"\nimport Downshift from \"downshift\"\nimport { IconButton } from \"./buttons\"\nimport { useCanvas } from \"./fabric-react\"\nimport FileUploader from \"./file-uploader\"\nimport { AdminOnly, CustomerOnly } from \"./controls-components\"\n\nconst Toolbar = ({\n  mode,\n  undo,\n  redo,\n  addText,\n  addImage,\n  preview,\n  cancelPreview,\n  save,\n  close,\n  addFramedImage\n}) => {\n  const inPreviewMode = mode === \"preview\"\n  const handlePreviewClick = inPreviewMode ? cancelPreview : preview\n\n  const nonNavIconClass = cx(inPreviewMode && \"opacity-50 pointer-events-none\")\n  const canvas = useCanvas()\n\n  return (\n    <div\n      className={cx(\n        \"p-1 flex justify-between\",\n        mode === \"crop\" && \"opacity-50 pointer-events-none\"\n      )}\n    >\n      <div className=\"sm:hidden\">\n        <IconButton\n          icon=\"times\"\n          color=\"red\"\n          onClick={close}\n          title=\"Close\"\n          tooltipPosition=\"bottom-right\"\n        />\n      </div>\n      <div className=\"flex space-x-1\">\n        <AdminOnly>\n          <AddDropdown\n            addFramedImage={addFramedImage}\n            addText={addText}\n            addImage={addImage}\n            className={nonNavIconClass}\n            canvas={canvas}\n          />\n        </AdminOnly>\n        <CustomerOnly>\n          <IconButton\n            icon=\"pencil\"\n            onClick={addText}\n            className={nonNavIconClass + \" sm:block hidden\"}\n            title=\"Add Text\"\n          >\n            <span className=\"text-sm hidden md:inline desktop-button-text\">\n              Add Text\n            </span>\n          </IconButton>\n\n          <FileUploader\n            onSuccess={addImage}\n            actionOptions={{\n              disableTransformer: true,\n              maxSize: 10 * 1024 * 1024, // 10 mb\n              startUploadingWhenMaxFilesReached: true,\n              imageMax: [canvas.width * 10, canvas.height * 10]\n            }}\n            customRender={({ onPick }) => (\n              <IconButton\n                icon=\"image\"\n                onClick={onPick}\n                className={nonNavIconClass + \" sm:block hidden\"}\n                title=\"Add Image\"\n              >\n                <span className=\"text-sm hidden md:inline desktop-button-text\">\n                  Add Image\n                </span>\n              </IconButton>\n            )}\n          />\n\n          <AddDropdown\n            addFramedImage={addFramedImage}\n            addText={addText}\n            addImage={addImage}\n            className={nonNavIconClass + \"sm:hidden block\"}\n            canvas={canvas}\n          />\n        </CustomerOnly>\n        <IconButton\n          icon=\"undo\"\n          onClick={undo}\n          className={nonNavIconClass}\n          title=\"Undo\"\n        >\n          <span className=\"text-sm hidden md:inline desktop-button-text\">\n            Undo\n          </span>\n        </IconButton>\n        <IconButton\n          icon=\"redo\"\n          onClick={redo}\n          className={nonNavIconClass}\n          title=\"Redo\"\n        >\n          <span className=\"text-sm hidden md:inline desktop-button-text\">\n            Redo\n          </span>\n        </IconButton>\n        <IconButton\n          icon=\"eye\"\n          active={inPreviewMode}\n          onClick={handlePreviewClick}\n          title=\"Preview\"\n        >\n          <span className=\"text-sm hidden md:inline desktop-button-text\">\n            Preview\n          </span>\n        </IconButton>\n        <div className=\"hidden sm:block\">\n          <Instructions />\n        </div>\n      </div>\n      <IconButton\n        buttonStyle=\"contained\"\n        className=\"button-contained-green\"\n        icon=\"check\"\n        onClick={save}\n        title=\"Save\"\n      >\n        <span className=\"text-sm hidden md:inline desktop-button-text\">\n          Done\n        </span>\n      </IconButton>\n    </div>\n  )\n}\n\nconst AddDropdown = ({\n  className,\n  addText,\n  addImage,\n  addFramedImage,\n  canvas\n}) => {\n  return (\n    <Downshift>\n      {({\n        getItemProps,\n        getMenuProps,\n        getToggleButtonProps,\n        getRootProps,\n        isOpen\n      }) => (\n        <div className=\"relative\">\n          <div {...getRootProps({}, { suppressRefError: true })}>\n            <IconButton\n              icon=\"plus\"\n              className={className}\n              title=\"Add text\"\n              {...getToggleButtonProps()}\n            >\n              <span className=\"text-sm hidden md:inline\">Add</span>\n            </IconButton>\n          </div>\n          {isOpen && (\n            <ul\n              {...getMenuProps()}\n              className=\"absolute z-10 bg-white rounded-lg shadow-xl w-32\"\n            >\n              <li\n                {...getItemProps({\n                  index: 0,\n                  onClick: addText,\n                  item: \"text\"\n                })}\n                className=\"px-4 py-2 cursor-pointer surface\"\n              >\n                Text\n              </li>\n              <FileUploader\n                onSuccess={addImage}\n                actionOptions={{\n                  disableTransformer: true,\n                  maxSize: 10 * 1024 * 1024, // 10 mb\n                  startUploadingWhenMaxFilesReached: true,\n                  imageMax: [canvas.width, canvas.height]\n                }}\n                customRender={({ onPick }) => (\n                  <li\n                    {...getItemProps({\n                      index: 1,\n                      onClick: onPick,\n                      item: \"image\"\n                    })}\n                    className=\"px-4 py-2 cursor-pointer surface\"\n                  >\n                    Image\n                  </li>\n                )}\n              />\n              <AdminOnly>\n                <li\n                  {...getItemProps({\n                    index: 0,\n                    onClick: addFramedImage,\n                    item: \"text\"\n                  })}\n                  className=\"px-4 py-2 cursor-pointer surface\"\n                >\n                  Framed Image\n                </li>\n              </AdminOnly>\n            </ul>\n          )}\n        </div>\n      )}\n    </Downshift>\n  )\n}\n\nconst Instructions = () => {\n  const { toggleProps, dropdownProps, isOpen } = useDropdown()\n\n  return (\n    <div className=\"relative\">\n      <IconButton icon=\"question\" title=\"Instructions\" {...toggleProps}>\n        <span className=\"text-sm hidden md:inline\">Instructions</span>\n      </IconButton>\n      {isOpen && (\n        <div\n          {...dropdownProps}\n          className=\"z-10 absolute bg-white rounded-lg shadow-xl w-56\"\n        >\n          <div className=\"p-5\">\n            <div className=\"font-bold text-sm mb-1\">Editing Text</div>\n            <ul className=\"list-disc list-inside\">\n              <li>\n                Click on a textbox to change its font, color, style and size.\n              </li>\n              <li>\n                Once selected, click again on the textbox to edit the text.\n              </li>\n            </ul>\n            <div className=\"font-bold text-sm mt-5 mb-1\">Editing Images</div>\n            <ul className=\"list-disc list-inside\">\n              <li>\n                Click on an image to change its size or replace it with another\n                image.\n              </li>\n            </ul>\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n\nexport default Toolbar\n","import { createPortal } from \"react-dom\"\nimport React, { useEffect, useRef } from \"react\"\nimport fabric from \"./fabric\"\nimport { Button } from \"./buttons\"\n\nconst getFullBounds = bounds => ({\n  ...bounds,\n  right: bounds.left + bounds.width,\n  bottom: bounds.top + bounds.height\n})\n\nconst getConstrainedBounds = (bounds, constraintBounds, padding = 0) => {\n  bounds = getFullBounds(bounds)\n  constraintBounds = getFullBounds(constraintBounds)\n\n  const top = Math.min(\n    Math.max(constraintBounds.top, bounds.top),\n    constraintBounds.bottom - padding\n  )\n  const left = Math.min(\n    Math.max(constraintBounds.left, bounds.left),\n    constraintBounds.right - padding\n  )\n  const right = Math.max(\n    Math.min(constraintBounds.right, bounds.right),\n    constraintBounds.left + padding\n  )\n  const bottom = Math.max(\n    Math.min(constraintBounds.bottom, bounds.bottom),\n    constraintBounds.top + padding\n  )\n\n  const width = right - left\n  const height = bottom - top\n\n  return {\n    top,\n    left,\n    width,\n    height\n  }\n}\n\nconst CropCanvas = ({\n  canvasDimensions,\n  controlsContainer,\n  containerDimensions,\n  target,\n  onCrop,\n  onCancel\n}) => {\n  const canvasEl = useRef()\n  const fabricCanvasRef = useRef(null)\n\n  /*\n   * Create two refs for storing references to the fabric\n   * objects we'll need to access in our callbacks.\n   */\n  const cropObject = useRef()\n  const imageObject = useRef()\n\n  /*\n   * This function prevents use from creating a new Canvas\n   * object on re-renders.\n   */\n  const getCanvas = () => {\n    if (fabricCanvasRef.current === null) {\n      fabricCanvasRef.current = new fabric.Canvas()\n    }\n\n    return fabricCanvasRef.current\n  }\n\n  const handleCrop = () => {\n    const cropBounds = cropObject.current.getBoundingRect(false, true)\n    const imageBounds = imageObject.current.getBoundingRect(false, true)\n    const imageCenterPoint = target.getCenterPoint()\n\n    target.set({\n      width: cropBounds.width / target.scaleX,\n      height: cropBounds.height / target.scaleY,\n      cropX: (cropBounds.left - imageBounds.left) / target.scaleX,\n      cropY: (cropBounds.top - imageBounds.top) / target.scaleY,\n      opacity: 1\n    })\n\n    if (target.angle !== 0) {\n      target.setPositionByOrigin(imageCenterPoint, \"center\", \"center\")\n    } else {\n      target.setPositionByOrigin(\n        new fabric.Point(cropBounds.left, cropBounds.top),\n        \"left\",\n        \"top\"\n      )\n    }\n\n    target.setCoords()\n\n    target.canvas.trigger(\"object:modified\")\n    target.canvas.setActiveObject(target).requestRenderAll()\n    onCrop()\n  }\n\n  const handleCancel = () => {\n    target.opacity = 1\n    target.canvas.setActiveObject(target).requestRenderAll()\n    onCancel()\n  }\n\n  /*\n   * Setup crop canvas\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n    canvas.initialize(canvasEl.current, {\n      width: canvasDimensions.width,\n      height: canvasDimensions.height,\n      selection: false,\n      uniScaleTransform: true\n    })\n\n    // For easy debugging\n    window.cropCanvas = canvas\n\n    return () => canvas.dispose()\n  }, [])\n\n  /*\n   * Add image and crop area rectangles\n   */\n  useEffect(() => {\n    // Clear the designer canvas selection\n    target.canvas.discardActiveObject().requestRenderAll()\n\n    const canvas = getCanvas()\n\n    /*\n     * Add a clone of the image to the crop canvas, restoring it\n     * to its original size.\n     */\n    target.clone(clonedImage => {\n      // Bounds of the canvas\n      const canvasBounds = {\n        top: 0,\n        left: 0,\n        width: canvas.width,\n        height: canvas.height\n      }\n\n      // Bounds of the image as it currently exists in the designer\n      const targetImageBounds = target.getBoundingRect(false, true)\n      const { height, width } = clonedImage.getOriginalSize()\n\n      target.opacity = 0\n      target.canvas.requestRenderAll()\n\n      clonedImage\n        .set({\n          cropX: null,\n          cropY: null,\n          height,\n          width,\n          selectable: false,\n          angle: 0\n        })\n        .setPositionByOrigin(\n          new fabric.Point(\n            targetImageBounds.left - target.cropX * target.scaleX,\n            targetImageBounds.top - target.cropY * target.scaleY\n          ),\n          \"left\",\n          \"top\"\n        )\n\n      // Bounds of the image restored to it's original size\n      const restoredImageBounds = clonedImage.setCoords().getBoundingRect()\n\n      // Bounds of the total croppable area\n      const croppableBounds = getConstrainedBounds(\n        restoredImageBounds,\n        canvasBounds\n      )\n\n      // Bounds of the initial crop area\n      const initialCropBounds = getConstrainedBounds(\n        targetImageBounds,\n        croppableBounds\n      )\n\n      const imageOverlay = new fabric.Rect({\n        fill: \"rgba(200,200,200,0.5)\",\n        ...restoredImageBounds,\n        selectable: false,\n        clipPath: new fabric.Rect({\n          ...initialCropBounds,\n          inverted: true,\n          absolutePositioned: true\n        })\n      })\n\n      const cropArea = new fabric.Rect({\n        fill: \"transparent\",\n        ...initialCropBounds,\n        borderColor: \"#3182ce\",\n        cornerColor: \"#3182ce\",\n        lockRotation: true,\n        lockUniScaling: false,\n        lockSkewingX: false,\n        lockSkewingY: false,\n        lockScalingFlip: true,\n        hasRotatingPoint: false,\n        centeredScaling: false,\n        minScaleLimit: 0.1\n      })\n\n      // Save references for easy access in callbacks\n      cropObject.current = cropArea\n      imageObject.current = clonedImage\n\n      canvas\n        .set({ backgroundColor: \"rgba(0,0,0,0.7)\" })\n        .add(clonedImage)\n        .add(imageOverlay)\n        .add(cropArea)\n        .setActiveObject(cropArea)\n        .requestRenderAll()\n\n      cropArea.on(\"moving\", () => {\n        const cropBounds = cropArea.getBoundingRect(false, true)\n        const fullCroppableBounds = getFullBounds(croppableBounds)\n\n        const top = Math.min(\n          fullCroppableBounds.bottom - cropBounds.height,\n          Math.max(fullCroppableBounds.top, cropBounds.top)\n        )\n\n        const left = Math.min(\n          fullCroppableBounds.right - cropBounds.width,\n          Math.max(fullCroppableBounds.left, cropBounds.left)\n        )\n\n        cropArea.set({\n          top,\n          left\n        })\n\n        imageOverlay.clipPath.set({\n          top,\n          left\n        })\n      })\n\n      cropArea.on(\"scaling\", () => {\n        const constrainedBounds = getConstrainedBounds(\n          cropArea.getBoundingRect(false, true),\n          croppableBounds\n        )\n\n        cropArea.set({\n          ...constrainedBounds,\n          scaleX: 1,\n          scaleY: 1\n        })\n\n        imageOverlay.clipPath.set(constrainedBounds)\n      })\n    })\n  }, [target])\n\n  /*\n   * Load specific dimensions into the canvas\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n    const scaleRatio = Math.min(\n      containerDimensions.width / canvasDimensions.width,\n      containerDimensions.height / canvasDimensions.height\n    )\n\n    canvas.setDimensions(\n      {\n        width: scaleRatio * canvasDimensions.width + \"px\",\n        height: scaleRatio * canvasDimensions.height + \"px\"\n      },\n      { cssOnly: true }\n    )\n\n    canvas.requestRenderAll()\n  }, [canvasDimensions])\n\n  return (\n    <div className=\"absolute inset-0 flex items-center justify-center\">\n      <canvas ref={canvasEl} tabIndex=\"0\"></canvas>\n      <CropControls\n        onCrop={handleCrop}\n        onCancel={handleCancel}\n        node={controlsContainer}\n      />\n    </div>\n  )\n}\n\n/*\n * Very ugly portla usage here. Ideally we would just invert control\n * so that the crop logic was nicely contained but still provided by\n * the top level designer component, but alas out of time today.\n */\nconst CropControls = ({ node, onCrop, onCancel }) =>\n  createPortal(\n    <div className=\"p-2 space-y-1\">\n      <Button onClick={onCrop} className=\"w-full button-contained-primary\">\n        Crop\n      </Button>\n      <Button onClick={onCancel} className=\"w-full\">\n        Cancel\n      </Button>\n    </div>,\n    node\n  )\n\nexport default CropCanvas\n","import { createPortal } from \"react-dom\"\nimport React, { useEffect, useRef } from \"react\"\nimport fabric from \"./fabric\"\nimport { Button } from \"./buttons\"\nimport FileUploader from \"./file-uploader\"\n\nconst CropCanvas = ({\n  canvasDimensions,\n  controlsContainer,\n  containerDimensions,\n  target,\n  onAdd,\n  onCancel,\n  medium\n}) => {\n  const canvasEl = useRef()\n  const fabricCanvasRef = useRef(null)\n\n  /*\n   * This function prevents use from creating a new Canvas\n   * object on re-renders.\n   */\n  const getCanvas = () => {\n    if (fabricCanvasRef.current === null) {\n      fabricCanvasRef.current = new fabric.Canvas()\n    }\n\n    return fabricCanvasRef.current\n  }\n\n  const insertImage = res => {\n    const canvas = getCanvas()\n    let url = res.filesUploaded[0].url\n    if (res.filesUploaded.length > 0) {\n      fabric.Image.fromURL(\n        url,\n        oImg => {\n          const rect = canvas.getActiveObject()\n          const rectScaledHeight = rect.height * rect.scaleY\n          const rectScaledWidth = rect.width * rect.scaleX\n\n          oImg.originX = \"left\"\n          oImg.originY = \"top\"\n          oImg.top = rect.top - (oImg.height - rectScaledHeight) / 2\n          oImg.left = rect.left - (oImg.width - rectScaledWidth) / 2\n          oImg.type = \"image\"\n          oImg.src = res.filesUploaded[0].url\n          oImg.crossOrigin = \"anonymous\"\n\n          rect.opacity = 1\n          rect.absolutePositioned = true\n\n          oImg.clipPath = rect\n          oImg.isFrame = true\n          oImg.opacity = 1\n          onAdd(oImg)\n        },\n        { crossOrigin: \"anonymous\" }\n      )\n    }\n  }\n\n  const finishEditClippingRect = () => {\n    const canvas = getCanvas()\n    let image = target\n    const rect = canvas.getActiveObject()\n    rect.opacity = 1\n    rect.absolutePositioned = true\n\n    image.clipPath = rect\n    image.canvas.setActiveObject(image).requestRenderAll()\n    onCancel()\n  }\n\n  const removeClipping = () => {\n    let image = target\n\n    image.clipPath = null\n    image.canvas.requestRenderAll()\n    onCancel()\n  }\n\n  /*\n   * Setup crop canvas\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n    canvas.initialize(canvasEl.current, {\n      width: canvasDimensions.width,\n      height: canvasDimensions.height,\n      selection: false,\n      uniScaleTransform: true\n    })\n\n    // For easy debugging\n    window.frameCanvas = canvas\n\n    return () => canvas.dispose()\n  }, [])\n\n  /*\n   * Load specific dimensions into the canvas\n   */\n  useEffect(() => {\n    const canvas = getCanvas()\n    const scaleRatio = Math.min(\n      containerDimensions.width / canvasDimensions.width,\n      containerDimensions.height / canvasDimensions.height\n    )\n\n    canvas.setDimensions(\n      {\n        width: scaleRatio * canvasDimensions.width + \"px\",\n        height: scaleRatio * canvasDimensions.height + \"px\"\n      },\n      { cssOnly: true }\n    )\n\n    canvas.requestRenderAll()\n  }, [canvasDimensions])\n\n  /*\n   * Create two refs for storing references to the fabric\n   * objects we'll need to access in our callbacks.\n   */\n  const invertedClipObject = useRef()\n  const clippingObject = useRef()\n  useEffect(() => {\n    const canvas = getCanvas()\n    let clippingRect\n    let angle = 0\n    if (target === null) {\n      clippingRect = new fabric.Rect({\n        left: canvas.width / 2 - 200,\n        top: canvas.height / 2 - 200,\n        originX: \"left\",\n        originY: \"top\",\n        width: 400,\n        height: 400,\n        angle: 0,\n        transparentCorners: false,\n        lockUniScaling: false,\n        lockSkewingX: false,\n        lockSkewingY: false,\n        lockScalingFlip: true,\n        hasRotatingPoint: true,\n        centeredScaling: false,\n        opacity: 0,\n        borderColor: \"#3182ce\",\n        cornerColor: \"#3182ce\"\n      })\n    } else {\n      // do editing stuff\n      angle = target.clipPath ? target.clipPath.angle : 0\n      let left = target.clipPath ? target.clipPath.left : target.aCoords.tl.x\n      let top = target.clipPath ? target.clipPath.top : target.aCoords.tl.y\n      let width = target.clipPath\n        ? target.clipPath.width * target.clipPath.scaleX\n        : target.width * target.scaleX\n      let height = target.clipPath\n        ? target.clipPath.height * target.clipPath.scaleY\n        : target.height * target.scaleY\n\n      clippingRect = new fabric.Rect({\n        left,\n        top,\n        width,\n        height,\n        angle,\n        originX: \"left\",\n        originY: \"top\",\n        transparentCorners: false,\n        opacity: 0,\n        borderColor: \"#3182ce\",\n        cornerColor: \"#3182ce\",\n        lockUniScaling: false,\n        lockSkewingX: false,\n        lockSkewingY: false,\n        lockScalingFlip: true,\n        hasRotatingPoint: true\n      })\n    }\n\n    let width = clippingRect.width\n    let height = clippingRect.height\n    let left = clippingRect.left\n    let top = clippingRect.top\n\n    const overlay = new fabric.Rect({\n      fill: \"rgba(200,200,200,0.7)\",\n      top: 0,\n      left: 0,\n      width: canvas.width,\n      height: canvas.height,\n      selectable: false,\n      opacity: 1,\n      clipPath: new fabric.Rect({\n        angle,\n        left,\n        top,\n        width,\n        height,\n        inverted: true,\n        absolutePositioned: true,\n        originX: \"left\",\n        originY: \"top\"\n      })\n    })\n\n    // Save references for easy access in callbacks\n    clippingObject.current = clippingRect\n    invertedClipObject.current = overlay\n\n    canvas\n      .add(overlay)\n      .add(clippingRect)\n      .setActiveObject(clippingRect)\n      .requestRenderAll()\n\n    clippingRect.on(\"rotating\", () => {\n      const { angle, left, top } = clippingRect\n      overlay.clipPath.set({\n        angle,\n        left,\n        top\n      })\n    })\n\n    clippingRect.on(\"moving\", () => {\n      const { top, left } = clippingRect\n      overlay.clipPath.set({\n        top,\n        left\n      })\n    })\n\n    clippingRect.on(\"scaling\", () => {\n      const { top, left, scaleX, scaleY } = clippingRect\n      overlay.clipPath.set({\n        scaleX: scaleX,\n        scaleY: scaleY,\n        left: left,\n        top: top\n      })\n    })\n  }, [])\n\n  return (\n    <div className=\"absolute inset-0 flex items-center justify-center\">\n      <canvas ref={canvasEl} tabIndex=\"0\"></canvas>\n      <CropControls\n        target={target}\n        onCancel={onCancel}\n        finishEditClippingRect={finishEditClippingRect}\n        insertImage={insertImage}\n        node={controlsContainer}\n        canvasDimensions={canvasDimensions}\n        removeClipping={removeClipping}\n      />\n    </div>\n  )\n}\n\n/*\n * Very ugly portla usage here. Ideally we would just invert control\n * so that the crop logic was nicely contained but still provided by\n * the top level designer component, but alas out of time today.\n */\nconst CropControls = ({\n  node,\n  insertImage,\n  onCancel,\n  canvasDimensions,\n  target,\n  finishEditClippingRect,\n  removeClipping\n}) =>\n  createPortal(\n    <div className=\"p-2 space-y-1\">\n      {target === null ? (\n        <FileUploader\n          onSuccess={insertImage}\n          actionOptions={{\n            disableTransformer: true,\n            maxSize: 10 * 1024 * 1024, // 10 mb\n            startUploadingWhenMaxFilesReached: true,\n            imageMax: [canvasDimensions.width, canvasDimensions.height]\n          }}\n          customRender={({ onPick }) => (\n            <Button onClick={onPick} className=\"w-full\">\n              Upload Image\n            </Button>\n          )}\n        />\n      ) : (\n        <Button onClick={finishEditClippingRect} className=\"w-full\">\n          Finish Clipping\n        </Button>\n      )}\n\n      {target !== null && (\n        <Button onClick={removeClipping} className=\"w-full\">\n          Remove Clipping\n        </Button>\n      )}\n      <Button onClick={onCancel} className=\"w-full\">\n        Cancel\n      </Button>\n    </div>,\n    node\n  )\n\nexport default CropCanvas\n","import React, { useEffect, useReducer, useRef, useState } from \"react\"\nimport useResizeObserver from \"use-resize-observer/polyfilled\"\nimport { useMousetrap } from \"../use-mousetrap\"\nimport { useFabric } from \"./fabric-react\"\nimport { ConfigContext, FabricContext } from \"./context\"\nimport Controls from \"./controls\"\nimport Toolbar from \"./toolbar\"\nimport fabric from \"./fabric\"\nimport {\n  Hidable,\n  LoadingContainer,\n  LoadingImage\n} from \"../components/spinner\"\nimport CropCanvas from \"./crop-canvas\"\nimport FrameCanvas from \"./frame-canvas\"\n\nconst initialState = {\n  isSaving: false,\n  showSafeArea: false,\n  mode: \"designer\",\n  previewUrl: null,\n  cropTarget: null,\n  frameTarget: null\n}\n\nconst reducer = (state, action) => {\n  switch (action.type) {\n    case \"save\":\n      return { ...state, isSaving: true }\n    case \"preview\":\n      return { ...state, previewUrl: action.url, mode: \"preview\" }\n    case \"cancelPreview\":\n      return { ...state, previewUrl: null, mode: \"designer\" }\n    case \"toggleSafeArea\":\n      return { ...state, showSafeArea: !state.showSafeArea }\n    case \"crop\":\n      return { ...state, cropTarget: action.target, mode: \"crop\" }\n    case \"framedImage\":\n      return { ...state, mode: \"frame\" }\n    case \"editFramedImage\":\n      return { ...state, mode: \"frame\", frameTarget: action.frameTarget }\n    case \"cancelFramedImage\":\n      return { ...state, mode: \"designer\", frameTarget: action.frameTarget }\n    case \"cancelCrop\":\n      return { ...state, cropTarget: null, mode: \"designer\" }\n    default:\n      return state\n  }\n}\n\nconst Canvas = ({ markup, sku, medium, onSave, onClose, isAdmin = false }) => {\n  const [state, dispatch] = useReducer(reducer, initialState)\n  const sideBarContainer = useRef(sideBarContainer)\n\n  /*\n   * Store the config context in a ref so we maintain referential identity\n   * during re-renders (we'd need to update these when props change if we\n   * wanted to support changing configuration mid design).\n   * See https://reactjs.org/docs/context.html#caveats\n   */\n  const config = useRef({ isAdmin, medium, sku })\n\n  const {\n    ref: containerRef,\n    width: containerWidth,\n    height: containerHeight\n  } = useResizeObserver()\n\n  const [canvasRef, fabricCanvas, isInitialized, isLoading] = useFabric({\n    markup,\n    medium,\n    isAdmin\n  })\n\n  // callback for framed-canvas to finish adding the object to fabricCanvas\n  const onFramedImage = oImg => {\n    fabricCanvas\n      .add(oImg)\n      .setActiveObject(oImg)\n      .requestRenderAll()\n    framedCancel()\n  }\n\n  // pull up framing canvas but in edit mode\n  const editFramedImage = target => {\n    dispatch({ type: \"editFramedImage\", frameTarget: target })\n    fabricCanvas.discardActiveObject().requestRenderAll()\n  }\n\n  // pulls up the framing canvas component\n  const addFramedImage = () => {\n    dispatch({ type: \"framedImage\" })\n  }\n\n  // unmounts framing canvas component\n  const framedCancel = () => {\n    dispatch({ type: \"cancelFramedImage\", frameTarget: null })\n  }\n\n  const cropImage = target => {\n    dispatch({ type: \"crop\", target })\n  }\n\n  const onCrop = () => {\n    dispatch({ type: \"cancelCrop\" })\n  }\n\n  const onCropCancel = () => {\n    dispatch({ type: \"cancelCrop\" })\n  }\n\n  const save = () => {\n    dispatch({ type: \"save\" })\n    fabricCanvas.save().then(onSave)\n  }\n\n  const preview = () => {\n    dispatch({ type: \"preview\" })\n    fabricCanvas\n      .preview(sku, medium)\n      .then(url => dispatch({ type: \"preview\", url }))\n  }\n\n  const cancelPreview = () => dispatch({ type: \"cancelPreview\" })\n\n  const undo = () => fabricCanvas.undo()\n  const redo = () => fabricCanvas.redo()\n\n  const addText = () => {\n    let text = new fabric.Textbox(\"Add Your Text\", {\n      fontSize: 100,\n      top: fabricCanvas.height / 2,\n      left: fabricCanvas.width * 0.1,\n      width: fabricCanvas.width * 0.8,\n      textAlign: \"center\",\n      type: \"textbox\"\n    })\n    fabricCanvas\n      .add(text)\n      .setActiveObject(text)\n      .requestRenderAll()\n  }\n\n  const addImage = res => {\n    if (res.filesUploaded.length > 0) {\n      let url = res.filesUploaded[0].url\n      fabric.Image.fromURL(\n        url,\n        oImg => {\n          oImg.top = (fabricCanvas.height - oImg.height) / 2\n          oImg.left = (fabricCanvas.width - oImg.width) / 2\n          oImg.type = \"image\"\n          oImg.src = url\n          oImg.crossOrigin = \"anonymous\"\n          fabricCanvas\n            .add(oImg)\n            .setActiveObject(oImg)\n            .requestRenderAll()\n        },\n        { crossOrigin: \"anonymous\" }\n      )\n    }\n  }\n\n  const [adminBleedHeight, setAdminBleedHeight] = useState(0)\n  const [adminBleedWidth, setBleedAdminWidth] = useState(0)\n\n  /*\n   * Resize the canvas when its containers width changes.\n   */\n  useEffect(() => {\n    if (containerWidth && containerHeight) {\n      const scaleRatio = Math.min(\n        containerWidth / markup.labelWidth,\n        containerHeight / markup.labelHeight\n      )\n\n      fabricCanvas.setDimensions(\n        {\n          width: scaleRatio * markup.labelWidth + \"px\",\n          height: scaleRatio * markup.labelHeight + \"px\"\n        },\n        { cssOnly: true }\n      )\n\n      if (isAdmin) {\n        setBleedAdminWidth(scaleRatio * markup.labelWidth - 19)\n        setAdminBleedHeight(scaleRatio * markup.labelHeight - 19)\n      }\n\n      // Hacking the prototype, disgusting but effective\n      fabric.Object.prototype.cornerSize = 25 / scaleRatio\n\n      fabricCanvas.requestRenderAll()\n    }\n  }, [\n    fabricCanvas,\n    markup.labelWidth,\n    markup.labelHeight,\n    containerWidth,\n    containerHeight\n  ])\n\n  /*\n   * Bind hotkeys\n   */\n  useMousetrap([\"ctrl+c\", \"command+c\"], fabricCanvas.copy)\n  useMousetrap([\"ctrl+v\", \"command+v\"], fabricCanvas.paste)\n  useMousetrap([\"ctrl+z\", \"command+z\"], undo)\n  useMousetrap([\"ctrl+shift+z\", \"command+shift+z\"], redo)\n\n  /*\n   * For quick debugging\n   */\n  window.fabricCanvas = fabricCanvas\n\n  return (\n    <ConfigContext.Provider value={config.current}>\n      <FabricContext.Provider value={fabricCanvas}>\n        <div className=\"designer font-sans relative h-full bg-white text-gray-900\">\n          <LoadingContainer\n            isLoading={!isInitialized || state.isSaving}\n            label={\n              (!isInitialized && \"Opening designer\") ||\n              (state.isSaving && \"Saving design\")\n            }\n            className=\"h-full flex flex-col\"\n          >\n            <div className=\"flex-none sticky top-0 z-20 bg-white shadow\">\n              <Toolbar\n                undo={undo}\n                redo={redo}\n                addText={addText}\n                addImage={addImage}\n                mode={state.mode}\n                preview={preview}\n                cancelPreview={cancelPreview}\n                save={save}\n                close={onClose}\n                addFramedImage={addFramedImage}\n              />\n            </div>\n            <div className=\"flex-1 min-h-0 bg-gray-200 shadow-inner\">\n              <Preview\n                active={state.mode === \"preview\"}\n                src={state.previewUrl}\n                cancel={cancelPreview}\n              />\n              <Hidable\n                hidden={\n                  state.mode !== \"designer\" &&\n                  state.mode !== \"crop\" &&\n                  state.mode !== \"frame\"\n                }\n                className=\"h-full flex sm:p-3 lg:p-5\"\n              >\n                <div className=\"fixed bottom-0 w-full z-10 sm:static sm:flex-none sm:w-64 sm:mr-3\">\n                  <div\n                    className=\"max-h-full w-full bg-white shadow-top sm:shadow sm:rounded sm:overflow-x-hidden sm:overflow-y-auto\"\n                    ref={sideBarContainer}\n                  >\n                    {isInitialized && (\n                      <Hidable hidden={state.mode !== \"designer\"}>\n                        <Controls\n                          medium={medium}\n                          canvas={fabricCanvas}\n                          cropImage={cropImage}\n                          editFramedImage={editFramedImage}\n                        />\n                      </Hidable>\n                    )}\n                  </div>\n                </div>\n                <div className=\"flex-1 designer-canvas-container p-3 sm:p-0\">\n                  <LoadingContainer\n                    isLoading={isLoading}\n                    label=\"Rendering design\"\n                    className=\"relative h-full w-full\"\n                  >\n                    <div\n                      className=\"absolute inset-0 flex items-center justify-center\"\n                      ref={containerRef}\n                    >\n                      {isAdmin && medium === \"label\" && (\n                        <div\n                          style={{\n                            width: adminBleedWidth,\n                            height: adminBleedHeight,\n                            border: \"1px dashed red\",\n                            position: \"absolute\",\n                            zIndex: 10,\n                            pointerEvents: \"none\"\n                          }}\n                        />\n                      )}\n                      <canvas ref={canvasRef} tabIndex=\"0\"></canvas>\n                    </div>\n                    {state.cropTarget && (\n                      <CropCanvas\n                        canvasDimensions={{\n                          width: fabricCanvas.width,\n                          height: fabricCanvas.height\n                        }}\n                        containerDimensions={{\n                          width: containerWidth,\n                          height: containerHeight\n                        }}\n                        controlsContainer={sideBarContainer.current}\n                        target={state.cropTarget}\n                        onCrop={onCrop}\n                        onCancel={onCropCancel}\n                      />\n                    )}\n\n                    {/* \n                      rendering based on mode rather than a target because when first adding a framed image\n                      user will be drawing a rectangle for the target rather than starting with a target. \n                      \n                      Editing a framed object's \"mask\" will be when we are using the target attribute so that \n                        1) we can render the masking rectangle exactly where it needs to be \n                        2) we dont initialize in drawing-rectangle-mode in frame-canvas\n                    */}\n                    {state.mode === \"frame\" && (\n                      <FrameCanvas\n                        canvasDimensions={{\n                          width: fabricCanvas.width,\n                          height: fabricCanvas.height\n                        }}\n                        containerDimensions={{\n                          width: containerWidth,\n                          height: containerHeight\n                        }}\n                        target={state.frameTarget}\n                        controlsContainer={sideBarContainer.current}\n                        onAdd={onFramedImage}\n                        medium={medium}\n                        onCancel={framedCancel}\n                      />\n                    )}\n                  </LoadingContainer>\n                </div>\n              </Hidable>\n            </div>\n          </LoadingContainer>\n        </div>\n      </FabricContext.Provider>\n    </ConfigContext.Provider>\n  )\n}\n\nconst Preview = ({ active, src, cancel }) => (\n  <Hidable\n    hidden={!active}\n    className=\"h-full relative p-4 flex items-center justify-center text-gray-800\"\n  >\n    <LoadingImage\n      src={src}\n      label=\"Rendering preview\"\n      className=\"max-h-full max-w-full\"\n    />\n    <div className=\"absolute bottom-0 inset-x-0 mb-6 mx-6 sm:left-auto sm:right-0\">\n      <button\n        className=\"w-full opacity-75 sm:w-auto sm:opacity-100 px-4 py-2 bg-blue-600 text-white font-bold hover:bg-blue-800\"\n        onClick={cancel}\n      >\n        Return to designer\n      </button>\n    </div>\n  </Hidable>\n)\n\nexport default Canvas\n","import fabric from \"./fabric\"\n\n/*\n * We've had a few generations of designers, each with their own special\n * fabric objects. This parsers normalizes all those all idiosyncracies\n * into the current geneeration format.\n */\nconst parser = design => {\n  const canvas = JSON.parse(design.markup)\n\n  /* objects coming from lablr need to be offset to align\n   * correctly in the current generation */\n  const lablrMarginOffset = { x: 0, y: 0 }\n\n  if (design.size === \"bordeaux\") {\n    lablrMarginOffset[\"x\"] = 150\n  } else if (design.size === \"teardrop\") {\n    lablrMarginOffset[\"y\"] = 150\n  }\n\n  /* Check if we have a \"lablr-template-image\" and if we do, pull it into the\n   * canvas.backgroundImage */\n  const templateImage = canvas.objects.find(\n    o => o.type === \"lablr-template-image\"\n  )\n\n  if (templateImage) {\n    canvas.backgroundImage = normalizeAsBackgroundImage(templateImage, canvas)\n    canvas.objects = canvas.objects.filter(o => o !== templateImage)\n  }\n\n  if (canvas.objects.length > 0) {\n    /* Check if the first object is like a background image and if it is pull\n     * it into the canvas.backgroundImage */\n    if (isBackgroundImageLike(canvas.objects[0], canvas)) {\n      canvas.backgroundImage = normalizeAsBackgroundImage(\n        canvas.objects[0],\n        canvas\n      )\n      canvas.objects = canvas.objects.slice(1)\n    }\n\n    canvas.objects = canvas.objects.map(object =>\n      normalizeObject(object, canvas, lablrMarginOffset)\n    )\n  }\n\n  return canvas\n}\n\n/*\n * Frames - in lablr we had the lablr-frame objects, in the second\n * generation designer we had the presence of clipPaths.\n */\nconst normalizeObject = (object, canvas, lablrMarginOffset) => {\n  switch (object.type) {\n    /* Ensure crossOrigin flag is set */\n    case \"image\": {\n      // convert clipTo to clipPath\n      if (object.mask) {\n        let leftDiff = object.mask.left\n        let topDiff = object.mask.top\n\n        let width = object.mask.width * object.mask.scaleX\n        let height = object.mask.height * object.mask.scaleY\n\n        let top = -(height / 2) + topDiff\n        let left = -(width / 2) + leftDiff\n\n        let rect = new fabric.Rect({\n          left,\n          top,\n          width,\n          height,\n          transparentCorners: false,\n          angle: object.mask.angle,\n          borderColor: \"#3182ce\",\n          cornerColor: \"#3182ce\",\n          absolutePositioned: true\n        })\n        object.clipPath = rect\n        object.mask = null\n        object.clipTo = null\n        object.isFrame = true\n      }\n      if (isBackgroundImageLike(object, canvas)) {\n        return normalizeAsBackgroundImage(object, canvas)\n      } else {\n        return {\n          ...object,\n          crossOrigin: \"anonymous\"\n        }\n      }\n    }\n\n    /* Multiple \"background-image\" objects can be present in one\n     * design, so for the ones that don't get explicity pulled in\n     * to the canvas.backgroundImage, we convert it to a normal\n     * image that covers the entire canvas. */\n    case \"background-image\":\n      return normalizeAsBackgroundImage(object, canvas)\n\n    /* \"text-line\" was introduced in the second generation designer\n     * but since the introduction of the fabric native \"textbox\" is\n     * no longer needed and has a 1-1 correspondance. */\n    case \"text-line\":\n      return {\n        ...object,\n        type: \"textbox\"\n      }\n\n    /* Once used as a sort of background image. */\n    case \"lablr-template-image\":\n      return normalizeAsBackgroundImage(object, canvas)\n\n    /* Once wrapped fabric \"image\". */\n    case \"lablr-image\": {\n      return {\n        ...object,\n        type: \"image\",\n        crossOrigin: \"anonymous\",\n        left: object.left - lablrMarginOffset.x,\n        top: object.top - lablrMarginOffset.y,\n        clipTo: null\n      }\n    }\n\n    case \"lablr-i-text-line\": {\n      const widthExtra = 50\n\n      return {\n        ...object,\n        type: \"textbox\",\n        left: object.left - lablrMarginOffset.x - widthExtra / 2,\n        top: object.top - lablrMarginOffset.y,\n        charSpacing: object.letterSpacing * 20,\n        backgroundColor: \"\",\n        width: object.width * object.scaleX + widthExtra,\n        scaleX: 1,\n        height: object.height * object.scaleY,\n        scaleY: 1\n      }\n    }\n\n    /* The \"lablr-frame\" consists of an object that is essentially a rectangle\n     * with a special \"image\" attribute that contained a \"lablr-frame-image\".\n     *\n     * We parse the \"lablr-frame-image\" into an image object and then create\n     * a rectangle clipping path based on the top-level \"lablr-frame\" object.\n     *\n     * This creates the affect of an image that can be dragged around and scaled\n     * but will only show through the rectangalur clipping path. */\n    case \"lablr-frame\": {\n      // Create a clip path in the same position (offset adjusted) as\n      // the original fabric-frame\n      const clipPath = new fabric.Rect({\n        top: object.top - lablrMarginOffset.y,\n        left: object.left - lablrMarginOffset.x,\n        width: object.width * object.scaleX,\n        height: object.height * object.scaleY,\n        originX: object.originX,\n        originY: object.originY,\n        absolutePositioned: true\n      })\n\n      const image = new fabric.Image({\n        crossOrigin: \"anonymous\",\n        src: object.image.src\n      })\n\n      image.clipPath = clipPath\n\n      return {\n        ...image.toObject(),\n        left:\n          object.left -\n          lablrMarginOffset.x +\n          (object.width * object.scaleX) / 2 +\n          ((object.image.width * object.image.scaleX) / 2 + object.image.left),\n        top:\n          object.top -\n          lablrMarginOffset.y +\n          (object.height * object.scaleY) / 2 +\n          ((object.image.height * object.image.scaleY) / 2 + object.image.top),\n        originX: \"center\",\n        originY: \"center\",\n        scaleX: object.image.scaleX,\n        scaleY: object.image.scaleY,\n        width: object.image.width,\n        height: object.image.height,\n        crossOrigin: \"anonymous\",\n        isFrame: true\n      }\n    }\n  }\n\n  return object\n}\n\n/* Set the image to be the size of the canvas, turn off events\n * and selectability so objects can be selected behind it. */\nconst normalizeAsBackgroundImage = (object, canvas) => ({\n  ...object,\n  type: \"image\",\n  top: 0,\n  left: 0,\n  originX: \"left\",\n  originY: \"top\",\n  crossOrigin: \"anonymous\",\n  scaleX: canvas.labelWidth / object.width,\n  scaleY: canvas.labelHeight / object.height,\n  selectable: false,\n  evented: false,\n  clipTo: null\n})\n\n/*\n * Determine if this template should set the canvas backgroundImage\n * property with the first object, which we do it's either a \"background-image\"\n * object or if it is the exact dimensions of the canvas.\n */\nconst isBackgroundImageLike = (object, canvas) =>\n  object.type === \"background-image\" ||\n  (Math.round(object.width * object.scaleX) === canvas.labelWidth &&\n    Math.round(object.height * object.scaleY) === canvas.labelHeight)\n\nexport default parser\n","import \"../polyfill\"\nimport \"../styles/styles\"\nimport \"./icons\"\nimport ReactDOM from \"react-dom\"\nimport React from \"react\"\nimport Modal from \"../components/modal\"\nimport Designer from \"./canvas\"\nimport parse from \"./markup-parser\"\nimport { loadFonts } from \"./fonts\"\n\nloadFonts()\n\nconst closePrompt =\n  \"Are you sure you want to leave the designer? Any unsaved progress will be lost.\"\n\nexport const launchInModal = ({ design, sku, onSave, isAdmin }) => {\n  const element = document.createElement(\"div\")\n  document.body.appendChild(element)\n\n  const markup = parse(design)\n  const medium = design.medium\n\n  sku = checkSku(sku, design)\n\n  // Useful for debugging\n  window.markup = markup\n  window.design = design\n\n  const close = () => {\n    if (window.confirm(closePrompt)) {\n      ReactDOM.unmountComponentAtNode(element)\n    }\n  }\n\n  const wrappedOnSave = ({ markup, url }) => {\n    ReactDOM.unmountComponentAtNode(element)\n    onSave(markup, url)\n  }\n\n  ReactDOM.render(\n    <Modal size=\"lg\" onClose={close} focusOnProps={{ focusLock: true }}>\n      <Designer\n        markup={markup}\n        onClose={close}\n        onSave={wrappedOnSave}\n        isAdmin={isAdmin}\n        sku={sku}\n        medium={medium}\n      />\n    </Modal>,\n    element\n  )\n}\n\nconst size_array = {\n  bordeaux: \"WW-PF-PG-NV\",\n  square: \"WS-LM-PRO-NV\",\n  teardrop: \"WR-ATC-PN-18\",\n  woodbox_single: \"WB1-PLYWOOD\",\n  woodbox_double: \"WB2-PLYWOOD\t\",\n  woodbox_triple: \"WB3-PLYWOOD\t\",\n  woodbox_magnum: \"WB1-MAG-PLYWOOD\",\n  woodbox_photo_single: \"WB1-PLYWOOD-PHOTO\",\n  woodbox_photo_double: \"WB2-PLYWOOD-PHOTO\",\n  woodbox_photo_triple: \"WB3-PLYWOOD-PHOTO\t\",\n  woodbox_photo_magnum: \"WB1-MAG-PLYWOOD-PHOTO\t\",\n  veuve: \"WS-VC-CHP-NV\",\n  mini_square: \"GLASS-RED\"\n}\nconst checkSku = (sku, design) => {\n  if (sku) {\n    return sku\n  }\n  console.log(design.size)\n  Object.keys(size_array).forEach(key => {\n    if (key === design.size.replace(/ /g, \"_\")) {\n      sku = size_array[key]\n    }\n  })\n  return sku\n}\n"],"sourceRoot":""}