diff --git a/CHANGELOG.md b/CHANGELOG.md index e9eb32c..c2425bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 1.0.0-beta.9 - [UNRELEASED] ### Added - Support for named urls when sharing links to workspaces +- Ability to convert items to other types by right-clicking +- Ancestor items in context menus now stay tinted when their child menus are opened ### Fixed - An issue where the inspector started to scroll horisontally on overflow - Closing electron windows may cause a loop preventing user defaults from being saved diff --git a/app/components/ContextMenuItem/index.jsx b/app/components/ContextMenuItem/index.jsx index 791bc5e..082a271 100644 --- a/app/components/ContextMenuItem/index.jsx +++ b/app/components/ContextMenuItem/index.jsx @@ -20,7 +20,15 @@ const MOUSE_LEAVE_DELAY_MS = 150 export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => { const elRef = React.useRef() + + /* + Delayed hover is used for preventing unmounting of + child menus when the cursor leaves the item, + regular hover is used for tinting the item + */ + const [delayedHover, setDelayedHover] = React.useState(false) const [hover, setHover] = React.useState(false) + const childArr = Array.isArray(children) ? children : [children] const timeoutRef = React.useRef() @@ -29,12 +37,14 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => if (timeoutRef.current) { clearTimeout(timeoutRef.current) } + setDelayedHover(true) setHover(true) } function handleMouseLeave () { + setHover(false) timeoutRef.current = setTimeout(() => { - setHover(false) + setDelayedHover(false) }, MOUSE_LEAVE_DELAY_MS) } @@ -45,6 +55,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => } function handleFocus (e) { + setDelayedHover(true) setHover(true) } @@ -53,7 +64,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => return (
onClick()} @@ -69,7 +80,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => } { - hover && childArr.length > 0 + delayedHover && childArr.length > 0 ? ( {children} diff --git a/app/components/ContextMenuItem/style.css b/app/components/ContextMenuItem/style.css index 6bc2622..6b5af8e 100644 --- a/app/components/ContextMenuItem/style.css +++ b/app/components/ContextMenuItem/style.css @@ -29,7 +29,8 @@ --base-color: black; } -.ContextMenuItem:hover > .ContextMenuItem-text { +.ContextMenuItem:hover > .ContextMenuItem-text, +.ContextMenuItem.is-hovered > .ContextMenuItem-text { background: rgb(228, 228, 228); } diff --git a/package-lock.json b/package-lock.json index 92b88c3..0df8d58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4171,23 +4171,23 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -4203,12 +4203,41 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -6310,39 +6339,39 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -10488,12 +10517,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -10556,20 +10585,49 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", diff --git a/plugins/rundown/app/components/RundownList/index.jsx b/plugins/rundown/app/components/RundownList/index.jsx index 4a74947..28535c2 100644 --- a/plugins/rundown/app/components/RundownList/index.jsx +++ b/plugins/rundown/app/components/RundownList/index.jsx @@ -281,9 +281,7 @@ export function RundownList ({ console.warn('Dropped spec is missing type') return } - const itemId = await bridge.items.createItem(spec.type) - - bridge.items.applyItem(itemId, spec) + const itemId = await bridge.items.createItem(spec.type, spec?.data) bridge.commands.executeCommand('rundown.moveItem', rundownId, newIndex, itemId) } catch (_) { console.warn('Tried to drop an invalid spec') diff --git a/plugins/rundown/app/components/RundownListItem/index.jsx b/plugins/rundown/app/components/RundownListItem/index.jsx index 70a2925..be51318 100644 --- a/plugins/rundown/app/components/RundownListItem/index.jsx +++ b/plugins/rundown/app/components/RundownListItem/index.jsx @@ -128,6 +128,11 @@ export function RundownListItem ({ label: 'Add after', children: contextMenu.generateAddContextMenuItems(types, typeId => handleAdd(typeId)) }, + { + type: 'item', + label: 'Convert to', + children: contextMenu.generateAddContextMenuItems(types, typeId => handleConvertTo(typeId)) + }, { type: 'item', label: 'Create reference', @@ -189,6 +194,16 @@ export function RundownListItem ({ bridge.commands.executeCommand('rundown.moveItem', rundownId, index + 1, itemId) } + async function handleConvertTo (typeId) { + if (!item?.id) { + return + } + + await bridge.items.applyItem(item?.id, { + type: typeId + }) + } + async function handleCreateReference () { const newItemId = await bridge.items.createItem('bridge.types.reference')