UNPKG

@activecollab/components

Version:

ActiveCollab Components

355 lines (329 loc) 17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.messageComponents = exports.MessageDialog = exports.DocLinkContext = void 0; var _react = _interopRequireWildcard(require("react")); var _styledComponents = _interopRequireDefault(require("styled-components")); var _BreakPoints = require("../../components/BreakPoints"); var _Button = require("../../components/Button"); var _Columns = require("../../components/Columns"); var _IconButton = require("../../components/IconButton"); var _Icons = require("../../components/Icons"); var _InfoBox = require("../../components/InfoBox"); var _Media = require("../../components/Media"); var _Modal = require("../../components/Modal"); var _Styles = require("../../components/PortableText/Styles"); var _Row = require("../../components/Row"); var _Stack = require("../../components/Stack"); var _Tiles = require("../../components/Tiles"); var _TitledText = require("../../components/TitledText"); var _Tooltip = require("../../components/Tooltip"); var _Typography = require("../../components/Typography"); var _Typography2 = require("../../components/Typography/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 _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; } /** * The in-app message dialog, as a Presentation mock. * * Two pieces, mirroring how the product is split: * * - {@link MessageDialog} — the hollow dialog shell (width, closing, * feedback), built only from design-system parts. In the product this shell * lives in the application as `InAppMessageDialog`. * - {@link messageComponents} — a demo message element catalog injected into * the design-system Portable Text engine, exactly like the typed cards * injected into the hollow StackedCard shell. In the product the catalog is * application code; the presentation ships this demo copy so the stories * need no app imports. */ /* ---- the dialog shell ---------------------------------------------- */ var DIALOG_WIDTH = { sm: "520px", md: "720px", lg: "880px" }; /* Feedback — the thumbs up / down slot. Down-vote reuses the up icon, rotated (the DS set only ships ThumbUpOutlineIcon). */ var StyledFeedback = _styledComponents.default.div.withConfig({ displayName: "MessageDialog__StyledFeedback", componentId: "sc-1kt5lil-0" })(["display:flex;align-items:center;justify-content:center;gap:8px;padding:8px 24px 28px;", "{padding:4px 24px 24px;}.fb-question{margin-right:4px;}.fb-btn svg{width:18px;height:18px;}.fb-down svg{transform:rotate(180deg);}"], _BreakPoints.screenBelow.sm); var DialogFeedback = function DialogFeedback(_ref) { var onVote = _ref.onVote; var _useState = (0, _react.useState)(null), _useState2 = _slicedToArray(_useState, 2), voted = _useState2[0], setVoted = _useState2[1]; var vote = (0, _react.useCallback)(function (value) { setVoted(value); onVote === null || onVote === void 0 || onVote(value); }, [onVote]); return /*#__PURE__*/_react.default.createElement(StyledFeedback, null, voted ? /*#__PURE__*/_react.default.createElement(_Typography.Body2, { color: "secondary" }, "Thanks for your feedback!") : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.Body2, { color: "secondary", className: "fb-question" }, "Was this helpful?"), /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, { title: "Yes, helpful" }, /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, { type: "button", variant: "text gray", className: "fb-btn", "aria-label": "Yes, helpful", onClick: function onClick() { return vote("up"); } }, /*#__PURE__*/_react.default.createElement(_Icons.ThumbUpOutlineIcon, null))), /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, { title: "No, not helpful" }, /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, { type: "button", variant: "text gray", className: "fb-btn fb-down", "aria-label": "No, not helpful", onClick: function onClick() { return vote("down"); } }, /*#__PURE__*/_react.default.createElement(_Icons.ThumbUpOutlineIcon, null))))); }; /* The shell is behaviour only: it sizes itself, closes on click-outside / Esc (DS Modal) / the X, and shows the feedback slot when an onVote handler is supplied. Content is whatever the caller renders as children — usually the Portable Text engine with the demo catalog injected. */ var StyledDialog = _styledComponents.default.div.withConfig({ displayName: "MessageDialog__StyledDialog", componentId: "sc-1kt5lil-1" })(["position:relative;box-sizing:border-box;display:flex;flex-direction:column;width:calc(100% - 32px);max-width:", ";max-height:calc(100vh - 96px);margin:56px auto 40px;overflow-y:auto;background-color:var(--page-paper-main);color:var(--color-theme-900);border-radius:12px;box-shadow:var(--shadow-primary);", "{margin:16px auto;}.dlg-close{position:absolute;top:12px;right:12px;z-index:2;}.dlg-content{padding:40px;}", "{.dlg-content{padding:32px 20px 24px;}}"], function (_ref2) { var $size = _ref2.$size; return DIALOG_WIDTH[$size]; }, _BreakPoints.screenBelow.sm, _BreakPoints.screenBelow.sm); var MessageDialog = exports.MessageDialog = function MessageDialog(_ref3) { var open = _ref3.open, onClose = _ref3.onClose, _ref3$size = _ref3.size, size = _ref3$size === void 0 ? "md" : _ref3$size, onVote = _ref3.onVote, children = _ref3.children; return /*#__PURE__*/_react.default.createElement(_Modal.Modal, { open: open, onClose: onClose }, /*#__PURE__*/_react.default.createElement(StyledDialog, { $size: size }, /*#__PURE__*/_react.default.createElement("div", { className: "dlg-close" }, /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, { title: "Close" }, /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, { type: "button", variant: "text gray", "aria-label": "Close", onClick: onClose }, /*#__PURE__*/_react.default.createElement(_Icons.CancelCrossIcon, null)))), /*#__PURE__*/_react.default.createElement("div", { className: "dlg-content" }, children), onVote ? /*#__PURE__*/_react.default.createElement(DialogFeedback, { onVote: onVote }) : null)); }; /* ---- doc-link wiring ------------------------------------------------ */ /** How a doc-link mark opens its article (by a slug-like reference). The surface that renders the message supplies the handler — in the product it closes the dialog and opens the article Sheet. */ var DocLinkContext = exports.DocLinkContext = /*#__PURE__*/_react.default.createContext(function () { return undefined; }); /* ---- the demo message element catalog ------------------------------- */ /* Inline marks ------------------------------------------------------- */ /* interface-name — the name of an interface element, e.g. the Security page. */ var StyledInterfaceName = _styledComponents.default.span.withConfig({ displayName: "MessageDialog__StyledInterfaceName", componentId: "sc-1kt5lil-2" })(["padding:0 4px;border-radius:4px;background-color:var(--color-theme-300);color:var(--color-theme-900);font-weight:600;white-space:nowrap;"]); var InterfaceNameMark = function InterfaceNameMark(_ref4) { var children = _ref4.children; return /*#__PURE__*/_react.default.createElement(StyledInterfaceName, null, children); }; /* keyboard-key — a keyboard key cap. */ var StyledKeyboardKey = _styledComponents.default.kbd.withConfig({ displayName: "MessageDialog__StyledKeyboardKey", componentId: "sc-1kt5lil-3" })(["display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border:1px solid var(--border-primary);border-bottom-width:2px;border-radius:5px;background-color:var(--color-theme-200);color:var(--color-theme-900);font-family:ui-monospace,\"SFMono-Regular\",Menlo,Consolas,monospace;font-size:11px;font-weight:600;line-height:1;vertical-align:baseline;"]); var KeyboardKeyMark = function KeyboardKeyMark(_ref5) { var children = _ref5.children; return /*#__PURE__*/_react.default.createElement(StyledKeyboardKey, null, children); }; /* doc-link — an inline link that opens a full help article. The mark carries an article reference; the open behaviour comes from DocLinkContext, so the authored content stays declarative. */ /* Built on the engine's inline anchor so a doc-link sits in the sentence exactly like a default link mark — same size, weight and line box as the surrounding copy — just recoloured. */ var StyledDocLink = (0, _styledComponents.default)(_Styles.StyledLink).withConfig({ displayName: "MessageDialog__StyledDocLink", componentId: "sc-1kt5lil-4" })(["color:var(--color-secondary);text-decoration-color:var(--color-secondary);"]); var DocLinkMark = function DocLinkMark(_ref6) { var mark = _ref6.mark, children = _ref6.children; var openArticle = (0, _react.useContext)(DocLinkContext); return /*#__PURE__*/_react.default.createElement(StyledDocLink, { href: "#", onClick: function onClick(event) { event.preventDefault(); openArticle(mark === null || mark === void 0 ? void 0 : mark.article); } }, children); }; /* Component objects --------------------------------------------------- */ /* callout — rendered with the DS InfoBox; the catalog keeps its own tone vocabulary and maps it to InfoBox types. */ var CALLOUT_TYPE = { info: "default", note: "note", success: "success" }; var CalloutObject = function CalloutObject(_ref7) { var _ref8; var node = _ref7.node, children = _ref7.children; return /*#__PURE__*/_react.default.createElement(_InfoBox.InfoBox, { type: CALLOUT_TYPE[(_ref8 = node.tone) !== null && _ref8 !== void 0 ? _ref8 : "info"], title: node.title, showIcon: true }, children); }; /* button-reference — a real DS Button shown for reference as its own block, so a message can point at a button instead of screenshotting it. It is intentionally non-interactive. */ var StyledButtonReference = _styledComponents.default.div.withConfig({ displayName: "MessageDialog__StyledButtonReference", componentId: "sc-1kt5lil-5" })(["display:flex;.c-button{pointer-events:none;}"]); var ButtonReferenceObject = function ButtonReferenceObject(_ref9) { var _ref0; var node = _ref9.node; if (typeof node.label !== "string") { return null; } return /*#__PURE__*/_react.default.createElement(StyledButtonReference, { "aria-hidden": "true" }, /*#__PURE__*/_react.default.createElement(_Button.Button, { variant: (_ref0 = node.variant) !== null && _ref0 !== void 0 ? _ref0 : "primary", size: "small", type: "button", tabIndex: -1 }, node.label)); }; /* row — a horizontal run of blocks (e.g. two button references). */ var RowObject = function RowObject(_ref1) { var _ref10; var node = _ref1.node, children = _ref1.children; return /*#__PURE__*/_react.default.createElement(_Row.Row, { space: (_ref10 = node.space) !== null && _ref10 !== void 0 ? _ref10 : "sm" }, children); }; /* tiles — an equal-size mosaic of blocks. */ var TilesObject = function TilesObject(_ref11) { var _ref12; var node = _ref11.node, children = _ref11.children; return /*#__PURE__*/_react.default.createElement(_Tiles.Tiles, { columns: (_ref12 = node.columns) !== null && _ref12 !== void 0 ? _ref12 : 3, space: "md", collapseBelow: "sm" }, children); }; /* split — text beside media, with the one layout rule the messages follow: screenshots sit on the right, flat illustrations on the left. `widths` is authored as [text, media] and reordered with the columns. */ var SplitObject = function SplitObject(_ref13) { var _ref14; var node = _ref13.node, children = _ref13.children; var media = node.media; var widths = (_ref14 = node.widths) !== null && _ref14 !== void 0 ? _ref14 : [1, 1]; var textColumn = /*#__PURE__*/_react.default.createElement(_Stack.Stack, { space: "lg" }, children); // A split without media degrades to its text column instead of crashing. if (!(media !== null && media !== void 0 && media.src)) { return textColumn; } var screenshot = media.variant === "screenshot"; var mediaColumn = /*#__PURE__*/_react.default.createElement(_Media.Media, { src: media.src, alt: media.alt, variant: media.variant, caption: media.caption }); return /*#__PURE__*/_react.default.createElement(_Columns.Columns, { widths: screenshot ? widths : [...widths].reverse(), space: "xl", alignY: "center", collapseBelow: "md" }, screenshot ? textColumn : mediaColumn, screenshot ? mediaColumn : textColumn); }; /* Default-block overrides --------------------------------------------- */ /* The engine's defaults use Body 1 primary; the messages are designed on the quieter Body 2 secondary voice, so the catalog overrides the text blocks — demonstrating the `blocks` half of the injection contract. */ var ParagraphBlock = function ParagraphBlock(_ref15) { var children = _ref15.children; return /*#__PURE__*/_react.default.createElement(_Typography.Body2, { color: "secondary", lineHeight: "loose" }, children); }; var ListItemBlock = function ListItemBlock(_ref16) { var children = _ref16.children; return /*#__PURE__*/_react.default.createElement(_Typography2.Typography, { variant: "Body 2", as: "li", color: "secondary", lineHeight: "loose" }, children); }; /* Titled sections speak in the quiet Header2 subhead voice rather than the engine's default Title2 for level 2, and keep a roomier rhythm between a titled section's content nodes. */ var TitledTextBlock = function TitledTextBlock(_ref17) { var block = _ref17.block, children = _ref17.children; var _ref18 = block, title = _ref18.title, level = _ref18.level; return /*#__PURE__*/_react.default.createElement(_TitledText.TitledText, { title: title, variant: level === 1 ? "title1" : "header2" }, children ? /*#__PURE__*/_react.default.createElement(_Stack.Stack, { space: "sm" }, children) : undefined); }; /** The demo catalog the presentations inject into the Portable Text engine — the stand-in for the application's `messageComponents` map. */ var messageComponents = exports.messageComponents = { marks: { "interface-name": InterfaceNameMark, "keyboard-key": KeyboardKeyMark, "doc-link": DocLinkMark }, objects: { callout: CalloutObject, "button-reference": ButtonReferenceObject, row: RowObject, tiles: TilesObject, split: SplitObject }, blocks: { paragraph: ParagraphBlock, "list-item": ListItemBlock, "titled-text": TitledTextBlock } }; //# sourceMappingURL=MessageDialog.js.map