gwchq-textjam 0.5.9 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -62996,7 +62996,7 @@ __webpack_require__.r(__webpack_exports__);
62996
62996
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
62997
62997
  /* harmony export */ });
62998
62998
  // extracted by mini-css-extract-plugin
62999
- /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({"grey-rpi-grey-15":"#d5d7dc","grey-rpi-grey-40":"#9497a4","grey-rpi-grey-5":"#f1f2f3","grey-rpi-grey-70":"#4a4d59","grey-rpf-white":"#fff","row":"styles-module__row--XtAJr","treeItem":"styles-module__treeItem--kbyYk","itemContent":"styles-module__itemContent--663gn","itemTitle":"styles-module__itemTitle--a6Liw","itemButton":"styles-module__itemButton--oB91C","itemFocused":"styles-module__itemFocused--SmUbE","level-0":"styles-module__level-0--5PVOR","level-1":"styles-module__level-1--vTMYv","level-2":"styles-module__level-2--Xx8Ie","level-3":"styles-module__level-3--ySuP4","level-4":"styles-module__level-4--7uciy","level-5":"styles-module__level-5--AEspR","level-6":"styles-module__level-6--c28W9","level-7":"styles-module__level-7--gU++Q","level-8":"styles-module__level-8--dmg5P","level-9":"styles-module__level-9--X73V0","level-10":"styles-module__level-10--VAKPI","level-11":"styles-module__level-11--5rqim","level-12":"styles-module__level-12--8cLBy","level-13":"styles-module__level-13--qlzYN","level-14":"styles-module__level-14--Q7bCT","level-15":"styles-module__level-15---1KaW","level-16":"styles-module__level-16--BCkZb","level-17":"styles-module__level-17--tM3Ht","level-18":"styles-module__level-18--GkyjF","level-19":"styles-module__level-19--kxLhM","level-20":"styles-module__level-20--sIjDn","itemContentEdit":"styles-module__itemContentEdit--cNmeE","inputError":"styles-module__inputError--zb21a","errorMessage":"styles-module__errorMessage--IT3hQ","itemTooltip":"styles-module__itemTooltip--c5oiY"});
62999
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({"grey-rpi-grey-15":"#d5d7dc","grey-rpi-grey-40":"#9497a4","grey-rpi-grey-5":"#f1f2f3","grey-rpi-grey-70":"#4a4d59","grey-rpf-white":"#fff","row":"styles-module__row--XtAJr","treeItem":"styles-module__treeItem--kbyYk","itemContent":"styles-module__itemContent--663gn","itemTitle":"styles-module__itemTitle--a6Liw","itemButton":"styles-module__itemButton--oB91C","itemSelected":"styles-module__itemSelected--JLLW5","itemFocused":"styles-module__itemFocused--SmUbE","level-0":"styles-module__level-0--5PVOR","level-1":"styles-module__level-1--vTMYv","level-2":"styles-module__level-2--Xx8Ie","level-3":"styles-module__level-3--ySuP4","level-4":"styles-module__level-4--7uciy","level-5":"styles-module__level-5--AEspR","level-6":"styles-module__level-6--c28W9","level-7":"styles-module__level-7--gU++Q","level-8":"styles-module__level-8--dmg5P","level-9":"styles-module__level-9--X73V0","level-10":"styles-module__level-10--VAKPI","level-11":"styles-module__level-11--5rqim","level-12":"styles-module__level-12--8cLBy","level-13":"styles-module__level-13--qlzYN","level-14":"styles-module__level-14--Q7bCT","level-15":"styles-module__level-15---1KaW","level-16":"styles-module__level-16--BCkZb","level-17":"styles-module__level-17--tM3Ht","level-18":"styles-module__level-18--GkyjF","level-19":"styles-module__level-19--kxLhM","level-20":"styles-module__level-20--sIjDn","itemContentEdit":"styles-module__itemContentEdit--cNmeE","inputError":"styles-module__inputError--zb21a","errorMessage":"styles-module__errorMessage--IT3hQ","itemTooltip":"styles-module__itemTooltip--c5oiY"});
63000
63000
 
63001
63001
  /***/ }),
63002
63002
 
@@ -82856,13 +82856,16 @@ const Text_1 = __webpack_require__(82803);
82856
82856
  const stores_1 = __webpack_require__(32132);
82857
82857
  const Tooltip_1 = __importDefault(__webpack_require__(26982));
82858
82858
  const useHover_1 = __webpack_require__(78556);
82859
- const FileTreeActions = ({ hasExpandedNodes, }) => {
82859
+ const FileTreeActions = ({ hasExpandedNodes, treeId, }) => {
82860
82860
  const { expandAll, collapseAll, createComponent, importFiles, importFolder } = (0, react_1.useContext)(FileTreeContext_1.TreeContext);
82861
82861
  const isReadOnly = (0, stores_1.useAppSelector)((state) => state.editor.readOnly);
82862
82862
  const { hovered: toggleHovered, hoverProps: toggleHoverProps } = (0, useHover_1.useHover)();
82863
82863
  const { hovered: addFolderHovered, hoverProps: addFolderHoverProps } = (0, useHover_1.useHover)();
82864
82864
  const { hovered: addFileHovered, hoverProps: addFileHoverProps } = (0, useHover_1.useHover)();
82865
- return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.fileTreeActions, children: [hasExpandedNodes ? ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...toggleHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Collapse all folders", onClick: collapseAll, className: styles_module_scss_1.default.iconButton, children: (0, jsx_runtime_1.jsx)(minus_circle_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Collapse all folders", visible: toggleHovered, position: "bottom", strategy: "fixed", size: "fit" })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...toggleHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Expand all folders", onClick: expandAll, className: styles_module_scss_1.default.iconButton, children: (0, jsx_runtime_1.jsx)(plus_circle_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Expand all folders", visible: toggleHovered, position: "bottom", strategy: "fixed", size: "fit" })] })), (0, jsx_runtime_1.jsx)(Text_1.Text, { size: 12, weight: "medium", className: styles_module_scss_1.default.fileTreeActionsLabel, children: "Project files" }), !isReadOnly && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...addFolderHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Add folder", onClick: () => createComponent(ProjectTypes_1.ProjectComponentType.DIR), className: (0, classnames_1.default)([styles_module_scss_1.default.iconButtonFilled, styles_module_scss_1.default.iconButton]), children: (0, jsx_runtime_1.jsx)(add_folder_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Add folder", visible: addFolderHovered, position: "bottom", strategy: "fixed", size: "fit" })] }), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...addFileHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Add file", onClick: () => createComponent(ProjectTypes_1.ProjectComponentType.FILE), className: (0, classnames_1.default)([styles_module_scss_1.default.iconButtonFilled, styles_module_scss_1.default.iconButton]), children: (0, jsx_runtime_1.jsx)(add_file_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Add file", visible: addFileHovered, position: "bottom", strategy: "fixed", size: "fit" })] }), (0, jsx_runtime_1.jsx)(ImportButton_1.ImportButton, { importFiles: importFiles, importFolder: importFolder })] }))] }));
82865
+ const toggleLabel = hasExpandedNodes
82866
+ ? "Collapse all folders"
82867
+ : "Expand all folders";
82868
+ return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.fileTreeActions, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...toggleHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": toggleLabel, "aria-expanded": hasExpandedNodes, "aria-controls": treeId, onClick: hasExpandedNodes ? collapseAll : expandAll, className: styles_module_scss_1.default.iconButton, children: hasExpandedNodes ? ((0, jsx_runtime_1.jsx)(minus_circle_svg_1.default, { "aria-hidden": "true", focusable: "false" })) : ((0, jsx_runtime_1.jsx)(plus_circle_svg_1.default, { "aria-hidden": "true", focusable: "false" })) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: toggleLabel, visible: toggleHovered, position: "bottom", strategy: "fixed", size: "fit" })] }), (0, jsx_runtime_1.jsx)(Text_1.Text, { size: 12, weight: "medium", className: styles_module_scss_1.default.fileTreeActionsLabel, children: "Project files" }), !isReadOnly && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...addFolderHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Add folder", onClick: () => createComponent(ProjectTypes_1.ProjectComponentType.DIR), className: (0, classnames_1.default)([styles_module_scss_1.default.iconButtonFilled, styles_module_scss_1.default.iconButton]), children: (0, jsx_runtime_1.jsx)(add_folder_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Add folder", visible: addFolderHovered, position: "bottom", strategy: "fixed", size: "fit" })] }), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.tooltipWrapper, ...addFileHoverProps, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "Add file", onClick: () => createComponent(ProjectTypes_1.ProjectComponentType.FILE), className: (0, classnames_1.default)([styles_module_scss_1.default.iconButtonFilled, styles_module_scss_1.default.iconButton]), children: (0, jsx_runtime_1.jsx)(add_file_svg_1.default, { "aria-hidden": "true", focusable: "false" }) }), (0, jsx_runtime_1.jsx)(Tooltip_1.default, { message: "Add file", visible: addFileHovered, position: "bottom", strategy: "fixed", size: "fit" })] }), (0, jsx_runtime_1.jsx)(ImportButton_1.ImportButton, { importFiles: importFiles, importFolder: importFolder })] }))] }));
82866
82869
  };
82867
82870
  exports.FileTreeActions = FileTreeActions;
82868
82871
 
@@ -82898,7 +82901,7 @@ const BasicItemContent = ({ item, onOpenMenu, isMenuOpen, triggerRef, }) => {
82898
82901
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.itemContent, onContextMenu: (e) => {
82899
82902
  e.preventDefault();
82900
82903
  onOpenMenu({ x: e.clientX, y: e.clientY });
82901
- }, children: [(0, jsx_runtime_1.jsx)(ItemIcon_1.ItemIcon, { itemData: itemData }), (0, jsx_runtime_1.jsx)(Text_1.Text, { className: styles_module_scss_1.default.itemTitle, size: 12, draggable: true, ...hoverProps, children: item.getItemName() }), !isSharedProject && ((0, jsx_runtime_1.jsx)("button", { ref: triggerRef, type: "button", className: styles_module_scss_1.default.itemButton, "aria-label": `More actions for ${item.getItemName()}`, "aria-haspopup": "menu", "aria-expanded": isMenuOpen, onClick: (e) => {
82904
+ }, children: [(0, jsx_runtime_1.jsx)(ItemIcon_1.ItemIcon, { itemData: itemData }), (0, jsx_runtime_1.jsx)(Text_1.Text, { className: styles_module_scss_1.default.itemTitle, size: 12, draggable: true, ...hoverProps, children: item.getItemName() }), !isSharedProject && ((0, jsx_runtime_1.jsx)("button", { ref: triggerRef, type: "button", tabIndex: -1, className: styles_module_scss_1.default.itemButton, "aria-label": `More actions for ${item.getItemName()}`, "aria-haspopup": "menu", "aria-expanded": isMenuOpen, onClick: (e) => {
82902
82905
  e.stopPropagation();
82903
82906
  // Anchor to the button's box, not the click point: a keyboard
82904
82907
  // activation reports clientX/Y of 0.
@@ -83233,16 +83236,35 @@ const FileTreeItem = ({ item, guides, activeLevel, isContextMenuAvailable, }) =>
83233
83236
  const handleCloseContextMenu = () => {
83234
83237
  setIsContextMenuOpen(false);
83235
83238
  setContextMenuPosition({ x: 0, y: 0 });
83236
- // On close, return focus to the trigger button but only if focus was
83237
- // lost (e.g. Escape), not when an action moved it (rename input, modal).
83239
+ // Back to the row, not the button, which is outside the tab order — but
83240
+ // only if focus was lost (Escape), not moved on purpose (rename, modal).
83238
83241
  requestAnimationFrame(() => {
83239
83242
  const active = document.activeElement;
83240
83243
  if (!active || active === document.body) {
83241
- triggerRef.current?.focus();
83244
+ item.setFocused();
83245
+ item.getElement()?.focus();
83242
83246
  }
83243
83247
  });
83244
83248
  };
83245
- return ((0, jsx_runtime_1.jsx)("div", { ...item.getProps(), className: (0, classnames_1.default)(styles_module_scss_1.default.row, styles_module_scss_1.default[`level-${level}`]), style: {
83249
+ // Keyboard route to the menu, which is out of the tab order.
83250
+ const handleKeyDown = (e) => {
83251
+ const isMenuKey = e.key === "ContextMenu" ||
83252
+ (e.shiftKey && e.key === "F10") ||
83253
+ (e.altKey && e.key === "ArrowDown");
83254
+ if (!isMenuKey)
83255
+ return;
83256
+ if (e.target !== e.currentTarget)
83257
+ return; // the row itself, not a child
83258
+ // no ⋯ button rendered, no keyboard menu either
83259
+ const trigger = triggerRef.current;
83260
+ if (!trigger)
83261
+ return;
83262
+ e.preventDefault();
83263
+ item.setFocused();
83264
+ const rect = trigger.getBoundingClientRect();
83265
+ handleOpenContextMenu({ x: rect.left, y: rect.bottom });
83266
+ };
83267
+ return ((0, jsx_runtime_1.jsx)("div", { ...item.getProps(), onKeyDown: handleKeyDown, className: (0, classnames_1.default)(styles_module_scss_1.default.row, styles_module_scss_1.default[`level-${level}`]), style: {
83246
83268
  ["--guides-bg"]: layers.join(","),
83247
83269
  ["--guides-pos"]: positions.join(","),
83248
83270
  ["--guides-size"]: sizes.join(","),
@@ -83413,12 +83435,9 @@ const useFileTree = ({ projectFiles, onRename, onDrop, onOpenFile, rootId, readO
83413
83435
  itemInstance: {
83414
83436
  getProps: ({ item, prev }) => {
83415
83437
  const isFolder = item.isFolder();
83416
- const state = item.isExpanded() ? "expanded" : "collapsed";
83417
83438
  return {
83418
83439
  ...prev?.(),
83419
- ...(isFolder && {
83420
- "aria-label": `${item.getItemName()}, ${state}`,
83421
- }),
83440
+ ...(isFolder && { "aria-expanded": item.isExpanded() }),
83422
83441
  onClick: () => {
83423
83442
  item.setFocused();
83424
83443
  item.primaryAction();
@@ -83511,6 +83530,7 @@ const EditorTypes_1 = __webpack_require__(42108);
83511
83530
  const projectHelpers_1 = __webpack_require__(2610);
83512
83531
  const ProjectTypes_1 = __webpack_require__(27130);
83513
83532
  const stores_1 = __webpack_require__(32132);
83533
+ const announce_1 = __webpack_require__(29331);
83514
83534
  const downloadContent_1 = __webpack_require__(9879);
83515
83535
  const editorFsThunks_1 = __webpack_require__(71862);
83516
83536
  /** Custom hook for action handlers on top headless-tree functionality */
@@ -83522,6 +83542,8 @@ const useFileTreeActions = () => {
83522
83542
  const dispatch = (0, react_redux_1.useDispatch)();
83523
83543
  // Creating component draft is local-only, not persisted in Redux
83524
83544
  const [draft, setDraft] = (0, react_1.useState)(null);
83545
+ // A created item still waiting to be focused, once it renders in place.
83546
+ const [pendingFocusId, setPendingFocusId] = (0, react_1.useState)(null);
83525
83547
  const openTreeFile = (0, react_1.useCallback)((id) => {
83526
83548
  const isTab = (tab) => tab.type === EditorTypes_1.OpenedTabType.FILE && tab.id === id;
83527
83549
  const fileIndex = openedTabs.findIndex(isTab);
@@ -83649,13 +83671,37 @@ const useFileTreeActions = () => {
83649
83671
  const item = tree.getRenamingItem();
83650
83672
  if (!item)
83651
83673
  return;
83674
+ const id = item.getId();
83675
+ const isDraft = Boolean(draft && draft.id === id);
83652
83676
  // If any draft that is being created
83653
- if (draft && draft.id === item.getId()) {
83677
+ if (draft && isDraft) {
83654
83678
  const data = item.getItemData();
83655
83679
  saveNewComponent(data, draft.parentId);
83656
83680
  }
83657
83681
  tree.completeRenaming();
83658
- }, [tree, draft, saveNewComponent]);
83682
+ if (isDraft) {
83683
+ setPendingFocusId(id);
83684
+ return;
83685
+ }
83686
+ setFocusedItem(id);
83687
+ const renamedRow = tree.getItemInstance(id)?.getElement();
83688
+ if (renamedRow)
83689
+ (0, announce_1.describeFocusTarget)(renamedRow);
83690
+ }, [tree, draft, saveNewComponent, setFocusedItem]);
83691
+ // Runs on the render that first places a created item in its sorted position.
83692
+ (0, react_1.useEffect)(() => {
83693
+ if (!pendingFocusId)
83694
+ return;
83695
+ const element = tree.getItemInstance(pendingFocusId)?.getElement();
83696
+ if (!element?.isConnected)
83697
+ return;
83698
+ setPendingFocusId(null);
83699
+ setFocusedItem(pendingFocusId);
83700
+ if (document.activeElement === element)
83701
+ element.blur();
83702
+ (0, announce_1.describeFocusTarget)(element);
83703
+ element.focus();
83704
+ }, [pendingFocusId, projectComponents, tree, setFocusedItem]);
83659
83705
  const removeComponent = (0, react_1.useCallback)((id) => {
83660
83706
  const item = tree.getItemInstance(id);
83661
83707
  if (!item)
@@ -83701,6 +83747,7 @@ const FileTreeContext_1 = __webpack_require__(5323);
83701
83747
  const treeGuides_1 = __webpack_require__(35258);
83702
83748
  const EmptyStateMessage_1 = __webpack_require__(34898);
83703
83749
  const FileTree = () => {
83750
+ const treeId = (0, react_1.useId)();
83704
83751
  const projectComponents = (0, stores_1.useAppSelector)((state) => state.editor.project.components);
83705
83752
  const focussedFileIndex = (0, stores_1.useAppSelector)((state) => state.editor.focussedFileIndex);
83706
83753
  const openFiles = (0, stores_1.useAppSelector)((state) => state.editor.openedTabs);
@@ -83709,19 +83756,42 @@ const FileTree = () => {
83709
83756
  const treeItems = tree.getItems();
83710
83757
  const guidesByIndex = (0, treeGuides_1.getGuidesByIndex)(treeItems);
83711
83758
  const activeLevel = (0, treeGuides_1.getActiveLevel)(treeItems.find((it) => it.getId() === focusedItem) ?? null);
83712
- // Sync focused file in editor with focused item in tree
83759
+ // Selection, not focus: focus carries the tree's single tab stop, so pointing
83760
+ // it at the open file would make Tab land there instead of at the top.
83713
83761
  (0, react_1.useEffect)(() => {
83714
83762
  if (!openFiles || focussedFileIndex === undefined)
83715
83763
  return;
83716
83764
  const tab = openFiles[focussedFileIndex];
83717
- const focusedFileId = tab?.type === EditorTypes_1.OpenedTabType.FILE ? tab.id : undefined;
83718
- const projectFile = projectComponents.find((c) => c.id === focusedFileId);
83719
- if (projectFile && projectFile.id !== focusedItem) {
83720
- setFocusedItem(projectFile.id);
83721
- }
83765
+ const openFileId = tab?.type === EditorTypes_1.OpenedTabType.FILE ? tab.id : undefined;
83766
+ const projectFile = projectComponents.find((c) => c.id === openFileId);
83767
+ tree.setSelectedItems(projectFile ? [projectFile.id] : []);
83722
83768
  // react only to focussedFileIndex and openFiles changes
83723
83769
  // eslint-disable-next-line react-hooks/exhaustive-deps
83724
- }, [focussedFileIndex, openFiles, setFocusedItem]);
83770
+ }, [focussedFileIndex, openFiles]);
83771
+ // Collapsing a folder hides whatever was focused inside it, and a focusedItem
83772
+ // matching no rendered row drops the whole tree out of the tab order.
83773
+ (0, react_1.useEffect)(() => {
83774
+ if (focusedItem === null)
83775
+ return;
83776
+ if (treeItems.some((item) => item.getId() === focusedItem))
83777
+ return;
83778
+ setFocusedItem(null);
83779
+ }, [treeItems, focusedItem, setFocusedItem]);
83780
+ // The tab stop lives on focusedItem, which is remembered — so without this
83781
+ // every entry after the first lands on the focused item, not first one.
83782
+ const handleFocusLeavingTree = (event) => {
83783
+ const movedTo = event.relatedTarget;
83784
+ if (movedTo && event.currentTarget.contains(movedTo))
83785
+ return; // still inside
83786
+ // A missing relatedTarget can also mean the rename input just unmounted, so
83787
+ // wait a frame and clear only if focus really landed outside the tree.
83788
+ const container = event.currentTarget;
83789
+ requestAnimationFrame(() => {
83790
+ if (container.contains(document.activeElement))
83791
+ return;
83792
+ setFocusedItem(null);
83793
+ });
83794
+ };
83725
83795
  const treeCtx = {
83726
83796
  createComponent,
83727
83797
  cancelRenaming,
@@ -83736,7 +83806,7 @@ const FileTree = () => {
83736
83806
  removeComponent,
83737
83807
  importFolder,
83738
83808
  };
83739
- return ((0, jsx_runtime_1.jsxs)(FileTreeContext_1.TreeContext.Provider, { value: treeCtx, children: [(0, jsx_runtime_1.jsx)(FileTreeActions_1.FileTreeActions, { hasExpandedNodes: Boolean(tree.getState().expandedItems.length) }), treeItems.length > 0 ? ((0, jsx_runtime_1.jsxs)("div", { ...tree.getContainerProps("Project files"), className: styles_module_scss_1.default.tree, children: [treeItems.map((item, i) => ((0, jsx_runtime_1.jsx)(FileTreeItem_1.FileTreeItem, { item: item, guides: guidesByIndex[i], activeLevel: activeLevel, isContextMenuAvailable: !isReadOnly }, item.getId()))), (0, jsx_runtime_1.jsx)("div", { style: tree.getDragLineStyle(), className: styles_module_scss_1.default.dragline })] })) : ((0, jsx_runtime_1.jsx)(EmptyStateMessage_1.EmptyStateMessage, {}))] }));
83809
+ return ((0, jsx_runtime_1.jsxs)(FileTreeContext_1.TreeContext.Provider, { value: treeCtx, children: [(0, jsx_runtime_1.jsx)(FileTreeActions_1.FileTreeActions, { hasExpandedNodes: Boolean(tree.getState().expandedItems.length), treeId: treeItems.length > 0 ? treeId : undefined }), treeItems.length > 0 ? ((0, jsx_runtime_1.jsxs)("div", { ...tree.getContainerProps("Project files"), id: treeId, onBlur: handleFocusLeavingTree, className: styles_module_scss_1.default.tree, children: [treeItems.map((item, i) => ((0, jsx_runtime_1.jsx)(FileTreeItem_1.FileTreeItem, { item: item, guides: guidesByIndex[i], activeLevel: activeLevel, isContextMenuAvailable: !isReadOnly }, item.getId()))), (0, jsx_runtime_1.jsx)("div", { style: tree.getDragLineStyle(), className: styles_module_scss_1.default.dragline })] })) : ((0, jsx_runtime_1.jsx)(EmptyStateMessage_1.EmptyStateMessage, {}))] }));
83740
83810
  };
83741
83811
  exports.FileTree = FileTree;
83742
83812
 
@@ -86445,10 +86515,13 @@ const react_redux_1 = __webpack_require__(14062);
86445
86515
  const EditorSlice_1 = __webpack_require__(68512);
86446
86516
  const stores_1 = __webpack_require__(32132);
86447
86517
  const createProjectArchive_1 = __webpack_require__(24133);
86518
+ const types_1 = __webpack_require__(92932);
86448
86519
  const useProjectRemix = ({ projectData, saveProject, }) => {
86449
86520
  const project = (0, stores_1.useAppSelector)((state) => state.editor.project);
86521
+ const saving = (0, stores_1.useAppSelector)((state) => state.editor.saving);
86450
86522
  const remixTriggered = (0, stores_1.useAppSelector)((state) => state.editor.remixTriggered);
86451
86523
  const codeRunTriggered = (0, stores_1.useAppSelector)((state) => state.editor.codeRunTriggered);
86524
+ const prevSavingRef = (0, react_1.useRef)(saving);
86452
86525
  const dispatch = (0, react_redux_1.useDispatch)();
86453
86526
  const remixStartedRef = (0, react_1.useRef)(false);
86454
86527
  (0, react_1.useEffect)(() => {
@@ -86503,6 +86576,16 @@ const useProjectRemix = ({ projectData, saveProject, }) => {
86503
86576
  dispatch((0, EditorSlice_1.setRemixTriggered)(false));
86504
86577
  remixStartedRef.current = false;
86505
86578
  }, [dispatch, remixTriggered, project?.identifier, projectData?.identifier]);
86579
+ (0, react_1.useEffect)(() => {
86580
+ const prevSaving = prevSavingRef.current;
86581
+ prevSavingRef.current = saving;
86582
+ if (remixTriggered &&
86583
+ prevSaving !== types_1.SavingState.FAILED &&
86584
+ saving === types_1.SavingState.FAILED) {
86585
+ dispatch((0, EditorSlice_1.setRemixTriggered)(false));
86586
+ remixStartedRef.current = false;
86587
+ }
86588
+ }, [remixTriggered, saving, dispatch]);
86506
86589
  };
86507
86590
  exports.useProjectRemix = useProjectRemix;
86508
86591
 
@@ -87350,6 +87433,7 @@ exports["default"] = exports.UserSlice.reducer;
87350
87433
  Object.defineProperty(exports, "__esModule", ({ value: true }));
87351
87434
  exports.fsImportFolder = exports.fsImportFiles = exports.fsRemove = exports.fsAdd = exports.fsMove = exports.fsRename = void 0;
87352
87435
  const sendToast_1 = __webpack_require__(50068);
87436
+ const announce_1 = __webpack_require__(29331);
87353
87437
  const fileValidation_1 = __webpack_require__(59615);
87354
87438
  const planners_1 = __webpack_require__(5819);
87355
87439
  const utils_1 = __webpack_require__(33321);
@@ -87357,6 +87441,7 @@ const constants_1 = __webpack_require__(16287);
87357
87441
  const EditorTypes_1 = __webpack_require__(42108);
87358
87442
  const ProjectTypes_1 = __webpack_require__(27130);
87359
87443
  const macSystemFiles_1 = __webpack_require__(18213);
87444
+ const projectHelpers_1 = __webpack_require__(2610);
87360
87445
  const EditorSlice_1 = __webpack_require__(68512);
87361
87446
  const selectComponents = (state) => {
87362
87447
  return state.editor.project.components ?? [];
@@ -87370,6 +87455,30 @@ const DELETE_SUCCESS_TOAST = {
87370
87455
  [ProjectTypes_1.ProjectComponentType.DIR]: "The folder has been successfully deleted.",
87371
87456
  [ProjectTypes_1.ProjectComponentType.FILE]: "The file has been successfully deleted.",
87372
87457
  };
87458
+ // Screen-reader copy: shorter and single-line than the toasts.
87459
+ const kindOf = (component) => component.type === ProjectTypes_1.ProjectComponentType.DIR ? "Folder" : "File";
87460
+ const fileCount = (count) => `${count} ${count === 1 ? "file" : "files"}`;
87461
+ const withDuplicates = (summary, hasDuplicates) => hasDuplicates ? `${summary} Duplicate names were renamed.` : summary;
87462
+ const filesUploadedMessage = (uploaded, total, hasDuplicates, singleName) => {
87463
+ if (uploaded === 0) {
87464
+ return `Upload failed. ${fileCount(total)} could not be uploaded.`;
87465
+ }
87466
+ if (uploaded < total) {
87467
+ return withDuplicates(`${uploaded} of ${fileCount(total)} uploaded, ${total - uploaded} failed.`, hasDuplicates);
87468
+ }
87469
+ const summary = uploaded === 1 && singleName
87470
+ ? `${singleName} uploaded.`
87471
+ : `${fileCount(uploaded)} uploaded.`;
87472
+ return withDuplicates(summary, hasDuplicates);
87473
+ };
87474
+ const folderUploadedMessage = (folderName, uploaded, total, hasDuplicates) => {
87475
+ if (uploaded === 0)
87476
+ return `Folder ${folderName} could not be uploaded.`;
87477
+ const summary = uploaded === total
87478
+ ? `Folder ${folderName} uploaded with ${fileCount(uploaded)}.`
87479
+ : `Folder ${folderName} uploaded with ${uploaded} of ${fileCount(total)}, ${total - uploaded} failed.`;
87480
+ return withDuplicates(summary, hasDuplicates);
87481
+ };
87373
87482
  const hasCaseInsensitiveDuplicateNames = (files) => {
87374
87483
  const seen = new Set();
87375
87484
  for (const file of files) {
@@ -87385,8 +87494,16 @@ const fsRename = ({ id, parentId, newName, }) => (dispatch, getState) => {
87385
87494
  const state = getState();
87386
87495
  const components = selectComponents(state);
87387
87496
  const componentsMap = (0, utils_1.buildComponentsById)(components);
87497
+ const component = componentsMap.get(id);
87388
87498
  const patch = (0, planners_1.planRename)(id, parentId, newName, componentsMap);
87389
87499
  dispatch((0, EditorSlice_1.applyComponentsPatch)(patch));
87500
+ if (!component)
87501
+ return;
87502
+ // The tree creates items nameless and names them through this rename, so an
87503
+ // empty previous name means a create.
87504
+ (0, announce_1.announce)(component.name
87505
+ ? `${(0, projectHelpers_1.getFullComponentName)(component)} renamed to ${newName}`
87506
+ : `${kindOf(component)} ${newName} created`);
87390
87507
  };
87391
87508
  exports.fsRename = fsRename;
87392
87509
  const fsMove = ({ id, parentId }) => (dispatch, getState) => {
@@ -87394,8 +87511,15 @@ const fsMove = ({ id, parentId }) => (dispatch, getState) => {
87394
87511
  const components = selectComponents(state);
87395
87512
  const componentsMap = (0, utils_1.buildComponentsById)(components);
87396
87513
  const parentByChildId = (0, utils_1.buildParentByChildId)(components);
87514
+ const destination = componentsMap.get(parentId);
87397
87515
  const patch = (0, planners_1.planMove)(id, parentId, componentsMap, parentByChildId);
87398
87516
  dispatch((0, EditorSlice_1.applyComponentsPatch)(patch));
87517
+ // Absent from the patch means nothing moved. Use the planned name: it may
87518
+ // have been made unique in the new parent.
87519
+ const moved = patch.upsert.find((component) => component.id === id);
87520
+ if (moved && destination) {
87521
+ (0, announce_1.announce)(`${(0, projectHelpers_1.getFullComponentName)(moved)} moved to ${destination.name || "the project root"}`);
87522
+ }
87399
87523
  };
87400
87524
  exports.fsMove = fsMove;
87401
87525
  const fsAdd = ({ component, parentId, }) => (dispatch, getState) => {
@@ -87404,6 +87528,7 @@ const fsAdd = ({ component, parentId, }) => (dispatch, getState) => {
87404
87528
  if (component.type === ProjectTypes_1.ProjectComponentType.FILE &&
87405
87529
  !(0, utils_1.validateProjectFilesCount)(components, 1)) {
87406
87530
  (0, sendToast_1.showError)(filesCountErrorMessage);
87531
+ (0, announce_1.announce)(filesCountErrorMessage);
87407
87532
  return;
87408
87533
  }
87409
87534
  const componentsMap = (0, utils_1.buildComponentsById)(components);
@@ -87412,6 +87537,7 @@ const fsAdd = ({ component, parentId, }) => (dispatch, getState) => {
87412
87537
  if (component.type === ProjectTypes_1.ProjectComponentType.FILE) {
87413
87538
  dispatch((0, EditorSlice_1.openFile)({ id: component.id }));
87414
87539
  }
87540
+ // Silent: the draft is nameless here, and fsRename announces the create.
87415
87541
  };
87416
87542
  exports.fsAdd = fsAdd;
87417
87543
  const fsRemove = (id) => (dispatch, getState) => {
@@ -87429,8 +87555,10 @@ const fsRemove = (id) => (dispatch, getState) => {
87429
87555
  dispatch((0, EditorSlice_1.closeFile)({ id }));
87430
87556
  });
87431
87557
  dispatch((0, EditorSlice_1.applyComponentsPatch)(patch));
87432
- if (component)
87558
+ if (component) {
87433
87559
  (0, sendToast_1.showSuccess)(DELETE_SUCCESS_TOAST[component.type]);
87560
+ (0, announce_1.announce)(`${kindOf(component)} ${(0, projectHelpers_1.getFullComponentName)(component)} deleted`);
87561
+ }
87434
87562
  };
87435
87563
  exports.fsRemove = fsRemove;
87436
87564
  const fsImportFiles = ({ files, parentId }) => async (dispatch, getState) => {
@@ -87442,10 +87570,12 @@ const fsImportFiles = ({ files, parentId }) => async (dispatch, getState) => {
87442
87570
  return;
87443
87571
  if (!(0, utils_1.validateProjectFilesCount)(components, importableFiles.length)) {
87444
87572
  (0, sendToast_1.showError)(filesCountErrorMessage);
87573
+ (0, announce_1.announce)(filesCountErrorMessage);
87445
87574
  return;
87446
87575
  }
87447
87576
  const { validFiles, importErrors } = (0, fileValidation_1.validateFiles)(importableFiles);
87448
87577
  const hasDuplicates = hasCaseInsensitiveDuplicateNames(validFiles);
87578
+ const summary = filesUploadedMessage(validFiles.length, importableFiles.length, hasDuplicates, validFiles[0]?.name);
87449
87579
  if (validFiles.length > 0) {
87450
87580
  (0, sendToast_1.showSuccess)(`Selected files uploaded successfully.\n${validFiles.length} of ${importableFiles.length} file(s) uploaded.`);
87451
87581
  if (hasDuplicates) {
@@ -87454,6 +87584,7 @@ const fsImportFiles = ({ files, parentId }) => async (dispatch, getState) => {
87454
87584
  }
87455
87585
  else {
87456
87586
  (0, sendToast_1.showError)(`Selected files couldn’t be uploaded.\n${importableFiles.length} file(s) failed to upload.`);
87587
+ (0, announce_1.announce)(summary);
87457
87588
  }
87458
87589
  for (const error of importErrors) {
87459
87590
  (0, sendToast_1.showError)(error.reason);
@@ -87468,6 +87599,7 @@ const fsImportFiles = ({ files, parentId }) => async (dispatch, getState) => {
87468
87599
  dispatch((0, EditorSlice_1.queueBinaryWrites)({
87469
87600
  writes: binaryWrites,
87470
87601
  }));
87602
+ (0, announce_1.announce)(summary);
87471
87603
  };
87472
87604
  exports.fsImportFiles = fsImportFiles;
87473
87605
  const fsImportFolder = ({ files, parentId }) => async (dispatch, getState) => {
@@ -87481,11 +87613,13 @@ const fsImportFolder = ({ files, parentId }) => async (dispatch, getState) => {
87481
87613
  return;
87482
87614
  if (!(0, utils_1.validateProjectFilesCount)(components, importableFiles.length)) {
87483
87615
  (0, sendToast_1.showError)(filesCountErrorMessage);
87616
+ (0, announce_1.announce)(filesCountErrorMessage);
87484
87617
  return;
87485
87618
  }
87486
87619
  const folderName = importableFiles[0]?.webkitRelativePath?.split("/")[0];
87487
87620
  const { validFiles, importErrors } = (0, fileValidation_1.validateFiles)(importableFiles);
87488
87621
  const hasDuplicates = hasCaseInsensitiveDuplicateNames(validFiles);
87622
+ const summary = folderUploadedMessage(folderName ?? "", validFiles.length, importableFiles.length, hasDuplicates);
87489
87623
  if (validFiles.length > 0) {
87490
87624
  (0, sendToast_1.showSuccess)(`Folder '${folderName}' upload complete.\n${validFiles.length} of ${importableFiles.length} file(s) uploaded successfully.`);
87491
87625
  if (hasDuplicates) {
@@ -87494,6 +87628,7 @@ const fsImportFolder = ({ files, parentId }) => async (dispatch, getState) => {
87494
87628
  }
87495
87629
  else {
87496
87630
  (0, sendToast_1.showError)(`'${folderName}' folder couldn't be uploaded.\n${importableFiles.length} file(s) failed to upload.`);
87631
+ (0, announce_1.announce)(summary);
87497
87632
  }
87498
87633
  for (const error of importErrors) {
87499
87634
  (0, sendToast_1.showError)(error.reason);
@@ -87511,6 +87646,7 @@ const fsImportFolder = ({ files, parentId }) => async (dispatch, getState) => {
87511
87646
  dispatch((0, EditorSlice_1.queueBinaryWrites)({
87512
87647
  writes: binaryWrites,
87513
87648
  }));
87649
+ (0, announce_1.announce)(summary);
87514
87650
  };
87515
87651
  exports.fsImportFolder = fsImportFolder;
87516
87652
 
@@ -88042,6 +88178,115 @@ class LeaveGuardController {
88042
88178
  exports.LeaveGuardController = LeaveGuardController;
88043
88179
 
88044
88180
 
88181
+ /***/ }),
88182
+
88183
+ /***/ 29331:
88184
+ /***/ ((__unused_webpack_module, exports) => {
88185
+
88186
+
88187
+ /**
88188
+ * Screen-reader status messages. Two rules: a message must
88189
+ * be a node inserted into a region already on the page, and a live region is
88190
+ * never heard while focus moves - hence describeFocusTarget().
88191
+ */
88192
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
88193
+ exports.resetAnnouncements = exports.describeFocusTarget = exports.announce = exports.FOCUS_SETTLE_MS = void 0;
88194
+ // How long a message waits for a focus target to claim it.
88195
+ exports.FOCUS_SETTLE_MS = 150;
88196
+ // How long a message stays in the DOM once read.
88197
+ const MESSAGE_TTL_MS = 5000;
88198
+ const HIDDEN_STYLE = "position:absolute;inline-size:1px;block-size:1px;margin:-1px;padding:0;" +
88199
+ "overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0";
88200
+ let live = null;
88201
+ // Not a live region: holds text referenced by aria-describedby.
88202
+ let descriptions = null;
88203
+ let pending = null;
88204
+ let claimable = null;
88205
+ let descriptionCount = 0;
88206
+ const mount = () => {
88207
+ if (live)
88208
+ return;
88209
+ const host = document.createElement("div");
88210
+ host.setAttribute("style", HIDDEN_STYLE);
88211
+ live = document.createElement("div");
88212
+ live.setAttribute("role", "alert");
88213
+ live.setAttribute("aria-live", "assertive");
88214
+ descriptions = document.createElement("div");
88215
+ host.append(live, descriptions);
88216
+ document.body.appendChild(host);
88217
+ };
88218
+ if (typeof document !== "undefined") {
88219
+ if (document.body)
88220
+ mount();
88221
+ else
88222
+ document.addEventListener("DOMContentLoaded", mount, { once: true });
88223
+ }
88224
+ const announce = (message) => {
88225
+ const text = message.replace(/\s+/g, " ").trim();
88226
+ if (!text)
88227
+ return;
88228
+ claimable = text;
88229
+ if (pending)
88230
+ clearTimeout(pending);
88231
+ pending = setTimeout(() => {
88232
+ pending = null;
88233
+ if (claimable === null || !live)
88234
+ return;
88235
+ const node = document.createElement("div");
88236
+ node.textContent = claimable;
88237
+ claimable = null;
88238
+ live.appendChild(node);
88239
+ setTimeout(() => node.remove(), MESSAGE_TTL_MS);
88240
+ }, exports.FOCUS_SETTLE_MS);
88241
+ };
88242
+ exports.announce = announce;
88243
+ const describeFocusTarget = (element) => {
88244
+ if (claimable === null || !descriptions)
88245
+ return;
88246
+ const text = claimable;
88247
+ claimable = null;
88248
+ if (pending) {
88249
+ clearTimeout(pending);
88250
+ pending = null;
88251
+ }
88252
+ const id = `textjam-status-${(descriptionCount += 1)}`;
88253
+ const node = document.createElement("div");
88254
+ node.id = id;
88255
+ node.textContent = text;
88256
+ descriptions.appendChild(node);
88257
+ element.setAttribute("aria-describedby", [element.getAttribute("aria-describedby"), id].filter(Boolean).join(" "));
88258
+ // Only describes the action just taken, so drop it on blur.
88259
+ const cleanup = () => {
88260
+ if (!node.isConnected)
88261
+ return;
88262
+ element.removeEventListener("blur", cleanup);
88263
+ const next = (element.getAttribute("aria-describedby") ?? "")
88264
+ .split(/\s+/)
88265
+ .filter(Boolean)
88266
+ .filter((token) => token !== id)
88267
+ .join(" ");
88268
+ if (next)
88269
+ element.setAttribute("aria-describedby", next);
88270
+ else
88271
+ element.removeAttribute("aria-describedby");
88272
+ node.remove();
88273
+ };
88274
+ element.addEventListener("blur", cleanup);
88275
+ setTimeout(cleanup, MESSAGE_TTL_MS);
88276
+ };
88277
+ exports.describeFocusTarget = describeFocusTarget;
88278
+ /** Test helper: empties the regions and drops any pending message. */
88279
+ const resetAnnouncements = () => {
88280
+ if (pending)
88281
+ clearTimeout(pending);
88282
+ pending = null;
88283
+ claimable = null;
88284
+ live?.replaceChildren();
88285
+ descriptions?.replaceChildren();
88286
+ };
88287
+ exports.resetAnnouncements = resetAnnouncements;
88288
+
88289
+
88045
88290
  /***/ }),
88046
88291
 
88047
88292
  /***/ 5060:
package/dist/style.css CHANGED
@@ -690,7 +690,7 @@
690
690
  :root{--rpf-white: #ffffff}.styles-module__wrapper--NmEQI{display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1))}.styles-module__tooltipAnchor--nyFj4{position:relative}.styles-module__header--UkMi-{display:flex;align-items:center;justify-content:space-between;font-size:12px;block-size:62px;padding:calc(.625rem*var(--scale-factor, 1)) calc(1rem*var(--scale-factor, 1)) calc(.5rem*var(--scale-factor, 1)) calc(1.25rem*var(--scale-factor, 1));flex-shrink:0;z-index:699}.styles-module__headerBtn--kUJII{font-size:calc(.875rem*var(--scale-factor, 1));line-height:calc(1.25rem*var(--scale-factor, 1));font-weight:500;block-size:44px;padding:calc(.625rem*var(--scale-factor, 1)) calc(1.25rem*var(--scale-factor, 1));gap:7px}.styles-module__gwcLogo--svs9k{inline-size:calc(2.75rem*var(--scale-factor, 1))}.styles-module__textJamLogo--dZcnz{inline-size:150px;block-size:36px;margin-inline-start:calc(.75rem*var(--scale-factor, 1))}.styles-module__btnSvg--Ri2uZ{inline-size:44px;block-size:44px}.styles-module__projectName--6o3NT{flex-grow:1;min-inline-size:0;padding-inline-start:calc(1rem*var(--scale-factor, 1))}.styles-module__linkButton--bj6aP{color:#003046}.styles-module__sharedProject--baj0W{gap:calc(2rem*var(--scale-factor, 1))}.styles-module__remixBtnContent--sJf5m{display:flex;gap:calc(.5rem*var(--scale-factor, 1))}
691
691
  .resizable-with-handle__handle>div{position:relative;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0) !important}.resizable-with-handle__bar{display:block;background:var(--editor-color-text-secondary);border-radius:999px;pointer-events:auto}.resizable-with-handle__bar:focus{outline:none}.resizable-with-handle__bar:focus-visible{outline:2px auto Highlight;outline:2px auto -webkit-focus-ring-color;outline-offset:-1px}.resizable-with-handle__handle--right>div{inset-inline-end:3px !important}.resizable-with-handle__bar--right,.resizable-with-handle__bar--left{inline-size:4px;block-size:128px}.resizable-with-handle__handle--bottom>div{inset-block-end:3px !important}.resizable-with-handle__bar--bottom,.resizable-with-handle__bar--top{inline-size:128px;block-size:4px}
692
692
  :root{--rpf-white: #ffffff}.styles-module__sidebar--Fu5Qi{display:flex;position:relative;scrollbar-width:none}.styles-module__bar--fOlLf{display:flex;flex-direction:column;justify-content:space-between;margin:calc(1.5rem*var(--scale-factor, 1)) calc(1.25rem*var(--scale-factor, 1)) calc(.625rem*var(--scale-factor, 1)) calc(1.25rem*var(--scale-factor, 1))}.styles-module__optionsTop--2jNbs,.styles-module__optionsBottom--PtwF4{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(2rem*var(--scale-factor, 1))}.styles-module__option--MOGCu{display:flex;align-items:center;justify-content:center;box-sizing:border-box;inline-size:calc(2.75rem*var(--scale-factor, 1));block-size:calc(2.75rem*var(--scale-factor, 1));margin:0}.styles-module__option--MOGCu.styles-module__userOption--qGt5j{inline-size:calc(2.5rem*var(--scale-factor, 1));block-size:calc(2.5rem*var(--scale-factor, 1));border-radius:50%;color:#003046;font-weight:500;background-color:#fff;cursor:pointer}.styles-module__option--MOGCu.styles-module__userOption--qGt5j:hover{background-color:#fff}.styles-module__option--MOGCu svg{margin:0;color:#003046}.styles-module__option--MOGCu:hover{background-color:#cbcbcb}.styles-module__option--MOGCu.styles-module__selected--avjSK{background-color:#fff}.styles-module__option--MOGCu.styles-module__selected--avjSK:hover{background-color:#fff}.styles-module__optionTooltipWrapper--7BqNv{position:relative}.styles-module__optionTooltip--wNPIN{inset-block-start:50%;inset-inline-start:100%;margin-inline-start:calc(.5rem*var(--scale-factor, 1));transform:translateY(-50%)}.styles-module__panel--bHhSv{display:flex;flex-direction:column;border-radius:calc(.5rem*var(--scale-factor, 1));box-shadow:0px 4px 20px 0px rgba(0,0,0,.15);margin-inline-end:calc(.625rem*var(--scale-factor, 1));inline-size:inherit;background:var(--sidebar-panel-background)}.styles-module__panelsColumn--3qf\+3{display:flex;flex-direction:column;margin-inline-end:calc(.625rem*var(--scale-factor, 1))}.styles-module__panelsColumn--3qf\+3 .styles-module__panel--bHhSv{margin-inline-end:0;inline-size:100%;block-size:100%;min-block-size:0}.styles-module__panelsColumnTop--OKT\+V{min-block-size:0;margin-block-end:calc(.625rem*var(--scale-factor, 1))}.styles-module__panelsColumnTop--OKT\+V .resizable-with-handle__handle--bottom>div{inset-block-end:calc(-1*calc(0.625rem * var(--scale-factor, 1))) !important}.styles-module__panelsColumnFill--v\+VWp{display:flex;flex-direction:column;flex:1;min-block-size:0}.styles-module__panelWithFooter--5ItsY{padding-block-end:calc(2rem*var(--scale-factor, 1))}.styles-module__panelHeading--GRNt0{margin:0;font-size:calc(1.5rem*var(--scale-factor, 1));line-height:calc(2rem*var(--scale-factor, 1))}.styles-module__panelHeader--bAHfN{display:flex;flex-direction:column;gap:calc(1rem*var(--scale-factor, 1));padding-block-end:calc(1rem*var(--scale-factor, 1));margin-inline:calc(1rem*var(--scale-factor, 1));border-block-end:1px solid var(--sidebar-border)}.styles-module__panelContent--X7kot{flex:1;padding:calc(.75rem*var(--scale-factor, 1)) calc(1rem*var(--scale-factor, 1));overflow-y:auto;scrollbar-width:thin}.styles-module__panelButtons---y4S-{display:flex;flex-direction:column;gap:calc(1rem*var(--scale-factor, 1))}.styles-module__panelFooter--T1y-s{border-block-start:1px solid #d5d7dc;inset-block-end:0px;inline-size:100%;inline-size:-moz-available;inline-size:-webkit-stretch;inline-size:stretch;padding-inline:calc(1rem*var(--scale-factor, 1));background-color:#fff;border-end-end-radius:8px}
693
- :root{--rpf-white: #ffffff}.styles-module__row--XtAJr{position:relative;margin-block-end:calc(.25rem*var(--scale-factor, 1));--strong-guide-color: #33625e;--normal-guide-color: #e5e5e5;padding:1px}.styles-module__row--XtAJr::before{content:"";position:absolute;inset:calc(-1*.125rem*var(--scale-factor, 1));pointer-events:none;background-image:var(--guides-bg);background-position:var(--guides-pos);background-size:var(--guides-size);background-repeat:no-repeat}.styles-module__treeItem--kbyYk{display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;position:relative;cursor:pointer}.styles-module__itemContent--663gn{inline-size:100%;border-radius:4px;display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;padding:calc(.25rem*var(--scale-factor, 1)) calc(.5rem*var(--scale-factor, 1))}.styles-module__itemContent--663gn:hover{background:#e5f6f1}.styles-module__itemTitle--a6Liw{inline-size:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.styles-module__itemButton--oB91C{display:none;padding:0;border:none;background:none;color:inherit;cursor:pointer}.styles-module__itemButton--oB91C:focus-visible{outline:none}.styles-module__itemFocused--SmUbE .styles-module__itemContent--663gn{background-color:#c5ffe8}.styles-module__itemFocused--SmUbE .styles-module__itemButton--oB91C{display:flex}.styles-module__itemContent--663gn:hover .styles-module__itemButton--oB91C,.styles-module__itemContent--663gn:focus-within .styles-module__itemButton--oB91C{display:flex}.styles-module__level-0--5PVOR{padding-inline-start:0px}.styles-module__level-1--vTMYv{padding-inline-start:20px}.styles-module__level-2--Xx8Ie{padding-inline-start:40px}.styles-module__level-3--ySuP4{padding-inline-start:60px}.styles-module__level-4--7uciy{padding-inline-start:80px}.styles-module__level-5--AEspR{padding-inline-start:100px}.styles-module__level-6--c28W9{padding-inline-start:120px}.styles-module__level-7--gU\+\+Q{padding-inline-start:140px}.styles-module__level-8--dmg5P{padding-inline-start:160px}.styles-module__level-9--X73V0{padding-inline-start:180px}.styles-module__level-10--VAKPI{padding-inline-start:200px}.styles-module__level-11--5rqim{padding-inline-start:220px}.styles-module__level-12--8cLBy{padding-inline-start:240px}.styles-module__level-13--qlzYN{padding-inline-start:260px}.styles-module__level-14--Q7bCT{padding-inline-start:280px}.styles-module__level-15---1KaW{padding-inline-start:300px}.styles-module__level-16--BCkZb{padding-inline-start:320px}.styles-module__level-17--tM3Ht{padding-inline-start:340px}.styles-module__level-18--GkyjF{padding-inline-start:360px}.styles-module__level-19--kxLhM{padding-inline-start:380px}.styles-module__level-20--sIjDn{padding-inline-start:400px}.styles-module__itemContentEdit--cNmeE{--border-width: 1px;inline-size:100%;display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;padding:calc(.25rem*var(--scale-factor, 1) - var(--border-width)) calc(.5rem*var(--scale-factor, 1) - var(--border-width));border-radius:4px;border:var(--border-width) solid #43d6b9}.styles-module__itemContentEdit--cNmeE input{border:none;font-size:calc(.75rem*var(--scale-factor, 1));line-height:calc(1rem*var(--scale-factor, 1))}.styles-module__itemContentEdit--cNmeE input:focus,.styles-module__itemContentEdit--cNmeE input:focus-visible{outline:none}.styles-module__inputError--zb21a{border-color:#e0201c}.styles-module__errorMessage--IT3hQ{position:absolute;inset-block-start:100%;inset-inline-start:0;inline-size:100%;padding:calc(.5rem*var(--scale-factor, 1));margin-block-start:calc(.25rem*var(--scale-factor, 1));border:1px solid #e0201c;border-radius:8px;background-color:#ffd5ce;color:#242424;z-index:650;display:flex;align-items:flex-start;gap:calc(.5rem*var(--scale-factor, 1))}.styles-module__errorMessage--IT3hQ svg{color:#e0201c}.styles-module__itemTooltip--c5oiY{min-inline-size:auto}
693
+ :root{--rpf-white: #ffffff}.styles-module__row--XtAJr{position:relative;margin-block-end:calc(.25rem*var(--scale-factor, 1));--strong-guide-color: #33625e;--normal-guide-color: #e5e5e5;padding:1px}.styles-module__row--XtAJr::before{content:"";position:absolute;inset:calc(-1*.125rem*var(--scale-factor, 1));pointer-events:none;background-image:var(--guides-bg);background-position:var(--guides-pos);background-size:var(--guides-size);background-repeat:no-repeat}.styles-module__treeItem--kbyYk{display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;position:relative;cursor:pointer}.styles-module__itemContent--663gn{inline-size:100%;border-radius:4px;display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;padding:calc(.25rem*var(--scale-factor, 1)) calc(.5rem*var(--scale-factor, 1))}.styles-module__itemContent--663gn:hover{background:#e5f6f1}.styles-module__itemTitle--a6Liw{inline-size:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.styles-module__itemButton--oB91C{display:none;padding:0;border:none;background:none;color:inherit;cursor:pointer}.styles-module__itemButton--oB91C:focus-visible{outline:none}.styles-module__itemSelected--JLLW5 .styles-module__itemContent--663gn{background-color:#c5ffe8}.styles-module__itemSelected--JLLW5 .styles-module__itemButton--oB91C,.styles-module__itemFocused--SmUbE .styles-module__itemButton--oB91C{display:flex}.styles-module__itemContent--663gn:hover .styles-module__itemButton--oB91C,.styles-module__itemContent--663gn:focus-within .styles-module__itemButton--oB91C{display:flex}.styles-module__level-0--5PVOR{padding-inline-start:0px}.styles-module__level-1--vTMYv{padding-inline-start:20px}.styles-module__level-2--Xx8Ie{padding-inline-start:40px}.styles-module__level-3--ySuP4{padding-inline-start:60px}.styles-module__level-4--7uciy{padding-inline-start:80px}.styles-module__level-5--AEspR{padding-inline-start:100px}.styles-module__level-6--c28W9{padding-inline-start:120px}.styles-module__level-7--gU\+\+Q{padding-inline-start:140px}.styles-module__level-8--dmg5P{padding-inline-start:160px}.styles-module__level-9--X73V0{padding-inline-start:180px}.styles-module__level-10--VAKPI{padding-inline-start:200px}.styles-module__level-11--5rqim{padding-inline-start:220px}.styles-module__level-12--8cLBy{padding-inline-start:240px}.styles-module__level-13--qlzYN{padding-inline-start:260px}.styles-module__level-14--Q7bCT{padding-inline-start:280px}.styles-module__level-15---1KaW{padding-inline-start:300px}.styles-module__level-16--BCkZb{padding-inline-start:320px}.styles-module__level-17--tM3Ht{padding-inline-start:340px}.styles-module__level-18--GkyjF{padding-inline-start:360px}.styles-module__level-19--kxLhM{padding-inline-start:380px}.styles-module__level-20--sIjDn{padding-inline-start:400px}.styles-module__itemContentEdit--cNmeE{--border-width: 1px;inline-size:100%;display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));text-align:start;padding:calc(.25rem*var(--scale-factor, 1) - var(--border-width)) calc(.5rem*var(--scale-factor, 1) - var(--border-width));border-radius:4px;border:var(--border-width) solid #43d6b9}.styles-module__itemContentEdit--cNmeE input{border:none;font-size:calc(.75rem*var(--scale-factor, 1));line-height:calc(1rem*var(--scale-factor, 1))}.styles-module__itemContentEdit--cNmeE input:focus,.styles-module__itemContentEdit--cNmeE input:focus-visible{outline:none}.styles-module__inputError--zb21a{border-color:#e0201c}.styles-module__errorMessage--IT3hQ{position:absolute;inset-block-start:100%;inset-inline-start:0;inline-size:100%;padding:calc(.5rem*var(--scale-factor, 1));margin-block-start:calc(.25rem*var(--scale-factor, 1));border:1px solid #e0201c;border-radius:8px;background-color:#ffd5ce;color:#242424;z-index:650;display:flex;align-items:flex-start;gap:calc(.5rem*var(--scale-factor, 1))}.styles-module__errorMessage--IT3hQ svg{color:#e0201c}.styles-module__itemTooltip--c5oiY{min-inline-size:auto}
694
694
  :root{--rpf-white: #ffffff}.styles-module__textDelete--9Qu4T{color:#e0201c}
695
695
  :root{--rpf-white: #ffffff}.styles-module__toastContainer--SzERA{display:flex;align-items:flex-start;gap:calc(.875rem*var(--scale-factor, 1));color:#003046;font-size:calc(.875rem*var(--scale-factor, 1));line-height:calc(1.25rem*var(--scale-factor, 1));font-weight:500;overflow-wrap:anywhere}.styles-module__toastMessage--5Ze6a{flex-grow:1;white-space:pre-line}.styles-module__errorIcon--v90W6{color:#e0201c}.styles-module__successIcon--gCtAd{color:#527d7a}.styles-module__closeIcon--iZ9ey{color:#003046;cursor:pointer;flex-shrink:0}.styles-module__toastList--7K4rT{display:flex;flex-direction:column-reverse;block-size:calc(100vh - 62px - 1em);max-block-size:calc(100vh - 62px - 1em);overflow-y:auto;overscroll-behavior:contain;padding-inline-end:calc(.25rem*var(--scale-factor, 1));scrollbar-color:rgba(0,48,70,.2) rgba(0,0,0,0);scrollbar-width:thin}.styles-module__toastList--7K4rT::-webkit-scrollbar{inline-size:calc(.5rem*var(--scale-factor, 1))}.styles-module__toastList--7K4rT::-webkit-scrollbar-track{background:rgba(0,0,0,0)}.styles-module__toastList--7K4rT::-webkit-scrollbar-thumb{background-color:rgba(0,48,70,.2);border-radius:calc(.25rem*var(--scale-factor, 1))}.styles-module__toastList--7K4rT:hover .Toastify__progress-bar{animation-play-state:paused !important}.styles-module__toast--LJOJf{flex-shrink:0;max-block-size:none;overflow:visible;padding:calc(1.125rem*var(--scale-factor, 1)) !important}.styles-module__toastBody--0iN2Q{align-items:flex-start;margin:0}.styles-module__infoIcon--tva-x{color:#0d47a1}
696
696
  :root{--rpf-white: #ffffff}.styles-module__tree--KziAJ{max-inline-size:100%;min-block-size:100px;color:#33625e}.styles-module__fileTreeActions--k\+Wsd{display:flex;gap:calc(.5rem*var(--scale-factor, 1));align-items:center;margin-block-end:calc(1rem*var(--scale-factor, 1))}.styles-module__tooltipWrapper--wltXE{position:relative;z-index:650}.styles-module__fileTreeActionsLabel--dPZp4{flex-grow:1;color:#69746d}.styles-module__importButton--rcLUm{inline-size:calc(2.5rem*var(--scale-factor, 1))}.styles-module__importArrowIcon--3eOLN{margin-inline-start:calc(.25rem*var(--scale-factor, 1))}.styles-module__label--WY51f{margin:0;flex-grow:1}.styles-module__iconButton--6UIVe{border:none;display:flex;justify-content:center;align-items:center;cursor:pointer}.styles-module__iconButtonFilled--w2vJC{background-color:#e5f6f1;border-radius:calc(.5rem*var(--scale-factor, 1));min-inline-size:calc(2rem*var(--scale-factor, 1));block-size:calc(2rem*var(--scale-factor, 1));transition:background-color .2s ease-in-out}.styles-module__iconButtonFilled--w2vJC:hover{background-color:#d7e7e3}.styles-module__iconButtonFilled--w2vJC:active{background-color:rgba(0,0,0,0)}.styles-module__dragline--RXmTT{block-size:2px;margin-block-start:-1px;background-color:#003046}.styles-module__dragline--RXmTT ::before{content:"";position:absolute;inset-inline-start:0;inset-block-start:-3px;block-size:4px;inline-size:4px;background:#fff;border:2px solid #003046;border-radius:99px}.styles-module__emptyStateContainer--AnTAm{padding:calc(.75rem*var(--scale-factor, 1));display:flex;flex-direction:column;align-items:center;text-align:center;font-size:calc(.75rem*var(--scale-factor, 1));line-height:calc(1rem*var(--scale-factor, 1));font-weight:400;color:#69746d;gap:calc(.25rem*var(--scale-factor, 1))}.styles-module__emptyStateIcon--sDlxK{inline-size:calc(1.5rem*var(--scale-factor, 1));block-size:calc(1.5rem*var(--scale-factor, 1))}.styles-module__emptyStateMessage--OkPax{font-weight:700}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gwchq-textjam",
3
3
  "description": "Embeddable React editor used in Raspberry Pi text-based projects.",
4
- "version": "0.5.9",
4
+ "version": "0.5.11",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/GirlsFirst/gwchq-textjam",
7
7
  "author": "Girls Who Code HQ",