UNPKG

@activecollab/components

Version:

ActiveCollab Components

257 lines (242 loc) 15.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.verticalDivider = exports.isShapeTool = exports.ToolSurface = exports.ToolButton = exports.TOOL_HINTS = exports.StyledToolPill = exports.StyledHint = exports.StyledBottomDock = exports.SHAPE_TOOLS = exports.SHAPE_DEFAULT_SIZES = exports.DEFAULT_SHAPE_TOOL = exports.DEFAULT_PROJECT_ELEMENT_TOOL = exports.CARD_PREVIEW_HEIGHT = exports.BottomDock = void 0; var _react = _interopRequireWildcard(require("react")); var _styledComponents = _interopRequireDefault(require("styled-components")); var _IconButton = require("../../components/IconButton"); var _Icons = require("../../components/Icons"); var _Tooltip = require("../../components/Tooltip"); var _Typography = require("../../components/Typography"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } /* ------------------------------------------------------------------ */ /* Floating toolbar surfaces */ /* ------------------------------------------------------------------ */ /* A floating, rounded toolbar surface (paper + shadow). */ var ToolSurface = exports.ToolSurface = _styledComponents.default.div.withConfig({ displayName: "bottomDock__ToolSurface", componentId: "sc-1xsxwg0-0" })(["display:flex;align-items:center;gap:2px;padding:6px;border-radius:14px;background-color:var(--page-paper-main);box-shadow:0 6px 24px rgba(0,0,0,0.16);border:1px solid var(--border-primary);svg > [stroke],svg > g [stroke]{stroke:currentColor;}"]); /* vertical separator used inside the toolbars */ var verticalDivider = exports.verticalDivider = "\n .divider {\n width: 1px;\n height: 24px;\n background-color: var(--color-theme-400);\n margin: 0 6px;\n flex-shrink: 0;\n }\n"; var StyledBottomDock = exports.StyledBottomDock = _styledComponents.default.div.withConfig({ displayName: "bottomDock__StyledBottomDock", componentId: "sc-1xsxwg0-1" })(["position:absolute;left:50%;bottom:18px;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:10px;max-width:calc(100% - 32px);"]); /** * The floating second toolbar row — a small pill above the dock that holds the * members of one tool family (Circle / Rectangle / Triangle, or Task / Project). * * It is the same surface as the dock itself, so a family reads as an extension * of the button that opened it rather than as a different kind of UI. Only one * pill is ever up, because only one tool is ever armed. */ var StyledToolPill = exports.StyledToolPill = (0, _styledComponents.default)(ToolSurface).withConfig({ displayName: "bottomDock__StyledToolPill", componentId: "sc-1xsxwg0-2" })([""]); /* Reserve two Caption1 lines (2 × 16px) so showing/hiding the hint never shifts the dock; visibility keeps the reserved space when hidden. */ var StyledHint = exports.StyledHint = (0, _styledComponents.default)(_Typography.Caption1).withConfig({ displayName: "bottomDock__StyledHint", componentId: "sc-1xsxwg0-3" })(["text-align:center;padding:0 16px;min-height:32px;&.hint-hidden{visibility:hidden;}"]); /* Per-tool hint shown under the dock only while that tool is hovered. */ var TOOL_HINTS = exports.TOOL_HINTS = { circle: "Click to drop a default circle, or draw one to size. Press O for a circle.", roundedRectangle: "Click to drop a default rectangle, or draw one to size. Press R for a rectangle.", triangle: "Click to drop a default triangle, or draw one to size. Press Y for a triangle.", connector: "Drag from one element to another to connect them. Press C to connect.", projectElements: "Put a task or a project on the board — pick which above, then draw its card.", project: "Draw a box to place a project card, then pick the project it shows.", task: "Draw a box to place a task card, then pick the task it shows.", link: "Draw a box to place a link, or paste a URL anywhere. Press L for link.", file: "Draw a box to place a file, or drop one on the board. Press F for file.", sticky: "Click anywhere on the canvas to drop a sticky note. Press S for a sticky note.", text: "Click anywhere on the canvas to start typing. Press T for text.", draw: "Click and drag to draw freehand. Press D for the pen.", shapes: "Pick a shape above, then draw it on the board. Press R for a rectangle." }; /** * The armed board tool. Link, File, Project, Task and the three shapes are * wired — arming one turns the next canvas click into "drop the default-size * element here" and a drag into "draw one this big"; everything else stays a * mock, so the board is otherwise always in select mode. */ var SHAPE_TOOLS = exports.SHAPE_TOOLS = ["circle", "roundedRectangle", "triangle"]; var isShapeTool = exports.isShapeTool = function isShapeTool(tool) { return SHAPE_TOOLS.includes(tool); }; /** * What a dock button arms the instant its pill opens. * * Opening a family and choosing inside it are two separate decisions, and the * second one has a right answer often enough that asking for it every time is * just a toll: a shape is usually a rectangle, and the thing people put on a * board is usually a task. So the pill opens with that member already armed and * the gesture can start immediately — picking another member is a correction, * not a required step. */ var DEFAULT_SHAPE_TOOL = exports.DEFAULT_SHAPE_TOOL = "roundedRectangle"; var DEFAULT_PROJECT_ELEMENT_TOOL = exports.DEFAULT_PROJECT_ELEMENT_TOOL = "task"; /* What a plain click drops — mirrors DEFAULT_SHAPE_SIZES in new-activecollab-front, and is exactly what the hover preview promises. */ var SHAPE_DEFAULT_SIZES = exports.SHAPE_DEFAULT_SIZES = { roundedRectangle: { width: 100, height: 60 }, circle: { width: 80, height: 80 }, triangle: { width: 80, height: 80 } }; /* Cards are auto-height, so their hover preview uses the app's nominal wire height (DEFAULT_LINK_CARD_SIZE / DEFAULT_FILE_CARD_SIZE). */ var CARD_PREVIEW_HEIGHT = exports.CARD_PREVIEW_HEIGHT = 240; /** The kinds of card the draw gesture can place. */ var ToolButton = exports.ToolButton = function ToolButton(_ref) { var tip = _ref.tip, active = _ref.active, children = _ref.children, onClick = _ref.onClick, onMouseEnter = _ref.onMouseEnter, onMouseLeave = _ref.onMouseLeave; return /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, { title: tip }, /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, { variant: "text gray", active: active, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave }, children)); }; /* Bottom-centre tool dock: the family pill (when one is open), the main toolbar, and the shared hint line. The dock is anchored by its BOTTOM edge, so a pill appearing or disappearing grows the stack upwards and never moves the toolbar itself. */ var BottomDock = exports.BottomDock = function BottomDock(_ref2) { var activeTool = _ref2.activeTool, onToolChange = _ref2.onToolChange; var _useState = (0, _react.useState)(null), _useState2 = _slicedToArray(_useState, 2), hoverHint = _useState2[0], setHoverHint = _useState2[1]; var hoverProps = function hoverProps(tool) { return { onMouseEnter: function onMouseEnter() { return setHoverHint(TOOL_HINTS[tool]); }, onMouseLeave: function onMouseLeave() { return setHoverHint(null); } }; }; /* An armed tool keeps its hint up after the pointer leaves the dock — the gesture happens on the canvas, so that is exactly when the instruction is needed. */ var hint = hoverHint !== null && hoverHint !== void 0 ? hoverHint : activeTool === "select" ? null : TOOL_HINTS[activeTool]; /* Which pill is up. Both are DERIVED from the armed tool rather than kept as their own open/closed state: opening a pill always arms one of its members, so "a member of this family is armed" and "this pill is showing" are the same fact. Deriving it is what makes every way of leaving the family close the pill for free — another dock tool, Esc on the canvas, or the gesture finishing and disarming the tool. Two states could disagree; one cannot. */ var shapesOpen = isShapeTool(activeTool); var projectElementsOpen = activeTool === "task" || activeTool === "project"; return /*#__PURE__*/_react.default.createElement(StyledBottomDock, null, shapesOpen ? /*#__PURE__*/_react.default.createElement(StyledToolPill, null, /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Circle", active: activeTool === "circle", onClick: function onClick() { return onToolChange("circle"); } }, hoverProps("circle")), /*#__PURE__*/_react.default.createElement(_Icons.CircleIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Rectangle", active: activeTool === "roundedRectangle", onClick: function onClick() { return onToolChange("roundedRectangle"); } }, hoverProps("roundedRectangle")), /*#__PURE__*/_react.default.createElement(_Icons.RoundedRectangleIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Triangle", active: activeTool === "triangle", onClick: function onClick() { return onToolChange("triangle"); } }, hoverProps("triangle")), /*#__PURE__*/_react.default.createElement(_Icons.TriangleIcon, null))) : null, projectElementsOpen ? /*#__PURE__*/_react.default.createElement(StyledToolPill, null, /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Task", active: activeTool === "task", onClick: function onClick() { return onToolChange("task"); } }, hoverProps("task")), /*#__PURE__*/_react.default.createElement(_Icons.TaskIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Project", active: activeTool === "project", onClick: function onClick() { return onToolChange("project"); } }, hoverProps("project")), /*#__PURE__*/_react.default.createElement(_Icons.ProjectIcon, null))) : null, /*#__PURE__*/_react.default.createElement(ToolSurface, null, /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, { title: "Sticky Note" }, /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, _extends({ variant: "text gray", onClick: function onClick() { return onToolChange("select"); } }, hoverProps("sticky")), /*#__PURE__*/_react.default.createElement(_Icons.NoteIcon, null))), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Text", onClick: function onClick() { return onToolChange("select"); } }, hoverProps("text")), /*#__PURE__*/_react.default.createElement(_Icons.TextIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Draw", onClick: function onClick() { return onToolChange("select"); } }, hoverProps("draw")), /*#__PURE__*/_react.default.createElement(_Icons.DrawIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Shape", active: shapesOpen, onClick: function onClick() { return onToolChange(shapesOpen ? "select" : DEFAULT_SHAPE_TOOL); } }, hoverProps("shapes")), /*#__PURE__*/_react.default.createElement(_Icons.ShapesIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Connect", onClick: function onClick() { return onToolChange("select"); } }, hoverProps("connector")), /*#__PURE__*/_react.default.createElement(_Icons.ConnectionIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Project Elements", active: projectElementsOpen, onClick: function onClick() { return onToolChange(projectElementsOpen ? "select" : DEFAULT_PROJECT_ELEMENT_TOOL); } }, hoverProps("projectElements")), /*#__PURE__*/_react.default.createElement(_Icons.ProjectStarIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "Link", active: activeTool === "link", onClick: function onClick() { return onToolChange(activeTool === "link" ? "select" : "link"); } }, hoverProps("link")), /*#__PURE__*/_react.default.createElement(_Icons.InsertLinkIcon, null)), /*#__PURE__*/_react.default.createElement(ToolButton, _extends({ tip: "File", active: activeTool === "file", onClick: function onClick() { return onToolChange(activeTool === "file" ? "select" : "file"); } }, hoverProps("file")), /*#__PURE__*/_react.default.createElement(_Icons.AttachmentIcon, null))), /*#__PURE__*/_react.default.createElement(StyledHint, { color: "tertiary", className: hint ? undefined : "hint-hidden" }, hint !== null && hint !== void 0 ? hint : " ")); }; //# sourceMappingURL=bottomDock.js.map