import { BORDER_RADIUS, COLORS } from "@heydovetail/ui-components"; import { extend, keyframes, types } from "typestyle"; import { style } from "typestyle-react"; import { CssClassName, DEFAULT_HIGHLIGHT_COLOR, PixelSize, TABLE } from "./constants"; const enum TableZindex { DEFAULT = 0, HOVER = 1, SELECTED = 2 } const tableCell: types.NestedCSSProperties = { border: `1px solid ${TABLE.BORDER}`, boxSizing: "border-box", minWidth: `${PixelSize.TABLE_CELL_MIN_WIDTH}px`, padding: `${PixelSize.TABLE_CELL_Y_PADDING}px ${PixelSize.TABLE_CELL_X_PADDING}px`, position: "relative", verticalAlign: "top", $nest: { [`& ul, & ol, & p, & .${CssClassName.ATTACHMENT}, & .${CssClassName.WEDGE_CURSOR}`]: { margin: "0.5em 0" } } }; const tableGutter: types.NestedCSSProperties = { cursor: "pointer", display: "block", background: TABLE.GUTTER_BACKGROUND, border: `1px solid ${TABLE.GUTTER_BORDER}`, minHeight: `${PixelSize.TABLE_GUTTER}px`, minWidth: `${PixelSize.TABLE_GUTTER}px`, position: "absolute", zIndex: TableZindex.DEFAULT }; function cssSvgDataUri(svg: string): string { return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`.replace("%20", " "); } const tablePimple: types.NestedCSSProperties = { background: `transparent center center no-repeat`, backgroundImage: cssSvgDataUri( `` ), backgroundSize: `${PixelSize.TABLE_PIMPLE_PUPIL}px`, backgroundPosition: "center center", display: "block", height: `${PixelSize.TABLE_PIMPLE}px`, position: "absolute", width: `${PixelSize.TABLE_PIMPLE}px`, $nest: { "&:hover": { cursor: "pointer" } } }; const tableInsertPimple = extend(tablePimple, { $nest: { "&:hover": { backgroundImage: cssSvgDataUri( `` ), backgroundSize: `${PixelSize.TABLE_PIMPLE_PLUS}px` } } }); const tableDeletePimple = extend(tablePimple, { $nest: { "&:hover": { backgroundImage: cssSvgDataUri( `` ), backgroundSize: `${PixelSize.TABLE_PIMPLE_CROSS}px` } } }); const edgeHighlight: types.NestedCSSProperties = { zIndex: 20, backgroundColor: TABLE.CELL_SELECTED_BORDER, pointerEvents: "none", position: "absolute" }; const p = { fontSize: "1em", lineHeight: "1.75em", margin: "0 0 1em" }; export const contentClassName = style({ color: COLORS.indigo, fontSize: "16px", position: "relative", $nest: { "& h1": { fontSize: "2em", fontWeight: 500, lineHeight: 1.25, margin: "2em 0 0.5em" }, "& h2": { fontSize: "1.5em", fontWeight: 500, lineHeight: 1.25, margin: "2em 0 0.5em" }, "& p": p, "& a": { color: COLORS.purple }, "& strong": { fontWeight: 600 }, "& ul, & ol": { margin: "1em 0", padding: "0 0 0 2em" }, [`& .${CssClassName.ATTACHMENT}`]: { display: "flex", marginBottom: "1em", userSelect: "none" }, [`& .${CssClassName.ATTACHMENT_INSERT_PREVIEW}`]: { color: "transparent", height: p.lineHeight, margin: p.margin, pointerEvents: "none", position: "relative", $nest: { "&:after": { content: '""', display: "block", position: "absolute", height: "2px", top: `calc(50% - 1px)`, width: "100%", background: COLORS.blue } } }, "& table": { borderCollapse: "collapse", fontSize: "14px", tableLayout: "fixed" }, [`& .${CssClassName.TABLE_WRAPPER}`]: { margin: "2em 0" }, "& th": extend(tableCell, { background: TABLE.HEADER_BACKGROUND, fontWeight: 600, textAlign: "left" }), "& td": tableCell, [`& .${CssClassName.TABLE_COLUMN_EDGE_HIGHLIGHT_LEFT}`]: extend(edgeHighlight, { left: -2, top: -1, bottom: -1, width: 3 }), [`& .${CssClassName.TABLE_COLUMN_EDGE_HIGHLIGHT_RIGHT}`]: extend(edgeHighlight, { right: -2, top: -1, bottom: -1, width: 3 }), [`& .${CssClassName.TABLE_ROW_EDGE_HIGHLIGHT_BOTTOM}`]: extend(edgeHighlight, { left: -1, right: -1, bottom: -2, height: 3 }), [`& .${CssClassName.TABLE_ROW_EDGE_HIGHLIGHT_TOP}`]: extend(edgeHighlight, { top: -2, left: -1, right: -1, height: 3 }), [`& .${CssClassName.TABLE_BETA_LOZENGE}`]: { position: "absolute", right: "0", top: "calc(100% + 4px)", $nest: { "&:after": { background: COLORS.i08, borderRadius: BORDER_RADIUS, color: COLORS.i60, display: "block", fontSize: "8px", fontWeight: "bold", lineHeight: "1em", padding: "3px 4px", content: '"BETA"' } } }, [`& .${CssClassName.TABLE_PIMPLE_ORIGIN}`]: extend(tableDeletePimple, { bottom: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, right: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)` }), [`& .${CssClassName.TABLE_COLUMN_PIMPLE}`]: extend(tableDeletePimple, { bottom: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, left: `calc(50% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_COLUMN_PIMPLE_RIGHT}`]: extend(tableInsertPimple, { bottom: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, left: `calc(100% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_COLUMN_PIMPLE_LEFT}`]: extend(tableInsertPimple, { bottom: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, right: `calc(100% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_ROW_PIMPLE}`]: extend(tableDeletePimple, { right: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, top: `calc(50% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_ROW_PIMPLE_BOTTOM}`]: extend(tableInsertPimple, { right: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, top: `calc(100% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_ROW_PIMPLE_TOP}`]: extend(tableInsertPimple, { right: `calc(100% + ${PixelSize.TABLE_GUTTER + PixelSize.TABLE_PIMPLE_MARGIN}px)`, bottom: `calc(100% - ${(PixelSize.TABLE_PIMPLE - PixelSize.TABLE_BORDER) >> 1}px)` }), [`& .${CssClassName.TABLE_GUTTER_AXIS_COLUMN}`]: extend(tableGutter, { borderLeftWidth: 0, borderRightWidth: 0, bottom: "100%", left: `-${PixelSize.TABLE_BORDER}px`, position: "absolute", right: `-${PixelSize.TABLE_BORDER}px`, $nest: { [`&.${CssClassName.TABLE_GUTTER_SELECTED}`]: { background: TABLE.GUTTER_SELECTED_BACKGROUND, borderColor: TABLE.CELL_SELECTED_BORDER, borderLeftWidth: `${PixelSize.TABLE_BORDER}px`, borderRightWidth: `${PixelSize.TABLE_BORDER}px`, zIndex: TableZindex.SELECTED } } }), [`& :last-child > .${CssClassName.TABLE_GUTTER_AXIS_COLUMN}`]: { borderTopRightRadius: PixelSize.TABLE_BORDER_RADIUS, borderRightWidth: `${PixelSize.TABLE_BORDER}px` }, [`& .${CssClassName.TABLE_GUTTER_AXIS_ROW}`]: extend(tableGutter, { borderTopWidth: 0, borderBottomWidth: 0, bottom: `-${PixelSize.TABLE_BORDER}px`, right: "100%", top: `-${PixelSize.TABLE_BORDER}px`, $nest: { [`&.${CssClassName.TABLE_GUTTER_SELECTED}`]: { background: TABLE.GUTTER_SELECTED_BACKGROUND, borderColor: TABLE.CELL_SELECTED_BORDER, borderTopWidth: `${PixelSize.TABLE_BORDER}px`, borderBottomWidth: `${PixelSize.TABLE_BORDER}px`, zIndex: TableZindex.SELECTED } } }), [`& tr:last-child .${CssClassName.TABLE_GUTTER_AXIS_ROW}`]: { borderBottomLeftRadius: PixelSize.TABLE_BORDER_RADIUS, borderBottomWidth: `${PixelSize.TABLE_BORDER}px` }, [`& .${CssClassName.TABLE_GUTTER_ORIGIN}`]: extend(tableGutter, { background: "white", borderTopLeftRadius: PixelSize.TABLE_BORDER_RADIUS, bottom: "100%", right: "100%", $nest: { "&:after": { border: `2px solid ${TABLE.ORIGIN_ICON}`, borderTopColor: "transparent", borderLeftColor: "transparent", bottom: "1px", content: '""', display: "block", height: 0, position: "absolute", right: "1px", width: 0 }, [`&.${CssClassName.TABLE_GUTTER_SELECTED}`]: { borderColor: TABLE.CELL_SELECTED_BORDER, zIndex: TableZindex.SELECTED, $nest: { "&:after": { borderColor: TABLE.GUTTER_SELECTED_BACKGROUND, borderTopColor: "transparent", borderLeftColor: "transparent" } } } } }), /* Give selected cells a blue overlay */ [`& .${CssClassName.TABLE_SELECTED_CELL}:after`]: { background: TABLE.CELL_SELECTED_BACKGROUND, border: `${PixelSize.TABLE_BORDER}px solid ${TABLE.CELL_SELECTED_BORDER}`, bottom: `-${PixelSize.TABLE_BORDER}px`, content: '""', left: `-${PixelSize.TABLE_BORDER}px`, pointerEvents: "none", position: "absolute", right: `-${PixelSize.TABLE_BORDER}px`, top: `-${PixelSize.TABLE_BORDER}px`, zIndex: TableZindex.SELECTED }, [`& .ProseMirror-focused .${CssClassName.WEDGE_CURSOR}`]: { display: "block" }, [`& .${CssClassName.WEDGE_CURSOR}`]: { color: "transparent", height: p.lineHeight, margin: p.margin, pointerEvents: "none", position: "relative", $nest: { "&:after": { content: '""', display: "block", position: "absolute", height: `calc(1.2 * ${p.fontSize})`, top: `calc(50% - (1.2 * ${p.fontSize}) / 2)`, width: "1px", background: "black", animationName: keyframes({ to: { visibility: "hidden" } }), animationDuration: "1.1s", animationIterationCount: "infinite", animationTimingFunction: "steps(2, start)" } } }, "& li p": { marginBottom: "0.5em" }, "& li ul, & li ol": { margin: "0" }, "& hr": { border: "none", margin: 0, marginBottom: "1em", padding: 0, // Line height is 1.75em, so we want half above and half below our line. // The line is 2px, so we take 1px off either side to stay centered. paddingBottom: "calc((1.75em / 2) - 1px)", paddingTop: "calc((1.75em / 2) - 1px)", $nest: { "&:after": { content: "' '", display: "block", height: "2px", backgroundColor: COLORS.i20 }, "&.ProseMirror-selectednode::after": { backgroundColor: COLORS.blue } } }, "& blockquote": { borderLeft: `4px solid ${COLORS.i20}`, color: COLORS.i60, margin: "0 0 1em 0", padding: "0.5em 0 0.5em 1em", $nest: { "& p": { // Having the normal 1em between paragraphs felt a bit spacious. marginBottom: "0.75em" }, "& p:last-child": { marginBottom: 0 } } }, "& .ProseMirror": { minHeight: "72px", outline: "none", // This is required by Firefox to prevent spaces from disappearing from // input when typing. whiteSpace: "pre-wrap", // This ensures the editor contains any bottom margin contributed by the // last content in the document. This ensures mouse-clicks at the bottom // of the document are captured by the editor, which allows a wedge cursor // to be placed at the bottom. paddingBottom: "1px", $nest: { [`&.${CssClassName.TABLE_RESIZE_CURSOR}`]: { cursor: ["ew-resize", "col-resize"] }, "&.ProseMirror-hideselection *::selection": { $unique: true, background: "transparent" }, "&.ProseMirror-hideselection *::-moz-selection": { $unique: true, background: "transparent" }, "&.ProseMirror-hideselection": { caretColor: "transparent" } as {}, // Waiting on https://github.com/typestyle/typestyle/commit/739069894ad21aaaa9ac22d6493c2fc6ffe0a092 [`&.${CssClassName.TAGGING_SELECTION_COLOR} *::-moz-selection`]: { $unique: true, background: DEFAULT_HIGHLIGHT_COLOR }, [`&.${CssClassName.TAGGING_SELECTION_COLOR} *::selection`]: { $unique: true, background: DEFAULT_HIGHLIGHT_COLOR } } } } });