Skip to content

Commit

Permalink
feat: Table row/column extension UI (#1172)
Browse files Browse the repository at this point in the history
* Added buttons to extend table rows/columns

* Added proper extend button implementations

* Fixed table handle menu buttons not preserving column widths

* Implemented PR feedback

* Implemented PR feedback

* Cleaned up code

* Updated test snapshots & fixes

* Added unit tests for column widths

* remaining todos

* prosemirror-tables upgrade

* show buttons when to right / bottom of table

* fix lint

* fix names

* fix small bugs

* fix drag handle

* fix safari support (will require prosemirror-tables upgrade

* add comment

* fix safari

---------

Co-authored-by: yousefed <[email protected]>
  • Loading branch information
matthewlipski and YousefED authored Oct 30, 2024
1 parent 8867e64 commit a5e82dd
Show file tree
Hide file tree
Showing 53 changed files with 2,186 additions and 271 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/ariakit/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { SuggestionMenuItem } from "./suggestionMenu/SuggestionMenuItem.js";
import { SuggestionMenuLabel } from "./suggestionMenu/SuggestionMenuLabel.js";
import { SuggestionMenuLoader } from "./suggestionMenu/SuggestionMenuLoader.js";
import { TableHandle } from "./tableHandle/TableHandle.js";
import { ExtendButton } from "./tableHandle/ExtendButton.js";
import { Toolbar } from "./toolbar/Toolbar.js";
import { ToolbarButton } from "./toolbar/ToolbarButton.js";
import { ToolbarSelect } from "./toolbar/ToolbarSelect.js";
Expand Down Expand Up @@ -81,6 +82,7 @@ export const components: Components = {
},
TableHandle: {
Root: TableHandle,
ExtendButton: ExtendButton,
},
Generic: {
Form: {
Expand Down
187 changes: 106 additions & 81 deletions packages/ariakit/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,181 +6,206 @@
@import "./ariakitStyles.css";

.bn-ak-input-wrapper {
align-items: center;
display: flex;
gap: 0.5rem;
align-items: center;
display: flex;
gap: 0.5rem;
}

.bn-toolbar .bn-ak-button {
width: unset;
width: unset;
}

.bn-toolbar .bn-ak-button[data-selected] {
padding-top: 0.125rem;
box-shadow: inset 0 0 0 1px var(--border), inset 0 2px 0 var(--border);
padding-top: 0.125rem;
box-shadow: inset 0 0 0 1px var(--border), inset 0 2px 0 var(--border);
}

.bn-toolbar .bn-ak-button[data-selected]:where(.dark, .dark *) {
box-shadow: inset 0 0 0 1px var(--border), inset 0 1px 1px 1px var(--shadow);
box-shadow: inset 0 0 0 1px var(--border), inset 0 1px 1px 1px var(--shadow);
}

.bn-toolbar .bn-ak-popover {
gap: 0.5rem;
gap: 0.5rem;
}

.bn-ariakit .bn-tab-panel {
align-items: center;
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: center;
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.bn-ariakit .bn-file-input {
max-width: 100%;
max-width: 100%;
}

.bn-ak-button {
outline-style: none;
outline-style: none;
}

.bn-ak-menu-item[aria-selected="true"],
.bn-ak-menu-item:hover {
background-color: hsl(204 100% 40%);
color: hsl(204 20% 100%);
background-color: hsl(204 100% 40%);
color: hsl(204 20% 100%);
}

.bn-ak-menu-item {
display: flex;
display: flex;
}

.bn-ariakit .bn-dropdown {
overflow: visible;
overflow: visible;
}

.bn-ariakit .bn-suggestion-menu {
height: fit-content;
max-height: 100%;
height: fit-content;
max-height: 100%;
}

.bn-ariakit .bn-color-picker-dropdown {
overflow: scroll;
overflow: scroll;
}

.bn-ak-suggestion-menu-item-body {
flex: 1;
flex: 1;
}

.bn-ak-suggestion-menu-item-subtitle {
font-size: 0.7rem;
font-size: 0.7rem;
}

.bn-ak-suggestion-menu-item-section[data-position="left"] {
padding: 8px;
padding: 8px;
}

.bn-ak-suggestion-menu-item-section[data-position="right"] {
--border: rgb(0 0 0/13%);
--highlight: rgb(255 255 255/20%);
--shadow: rgb(0 0 0/10%);
box-shadow: inset 0 0 0 1px var(--border), inset 0 2px 0 var(--highlight),
--border: rgb(0 0 0/13%);
--highlight: rgb(255 255 255/20%);
--shadow: rgb(0 0 0/10%);
box-shadow: inset 0 0 0 1px var(--border), inset 0 2px 0 var(--highlight),
inset 0 -1px 0 var(--shadow), 0 1px 1px var(--shadow);
font-size: 0.7rem;
border-radius: 4px;
padding-inline: 4px;
font-size: 0.7rem;
border-radius: 4px;
padding-inline: 4px;
}

.bn-ariakit .bn-grid-suggestion-menu {
background: var(--bn-colors-menu-background);
border-radius: var(--bn-border-radius-large);
box-shadow: var(--bn-shadow-medium);
display: grid;
gap: 7px;
height: fit-content;
justify-items: center;
max-height: min(500px, 100%);
overflow-y: auto;
padding: 20px;
background: var(--bn-colors-menu-background);
border-radius: var(--bn-border-radius-large);
box-shadow: var(--bn-shadow-medium);
display: grid;
gap: 7px;
height: fit-content;
justify-items: center;
max-height: min(500px, 100%);
overflow-y: auto;
padding: 20px;
}

.bn-ariakit .bn-grid-suggestion-menu-item {
align-items: center;
border-radius: var(--bn-border-radius-large);
cursor: pointer;
display: flex;
font-size: 24px;
height: 32px;
justify-content: center;
margin: 2px;
padding: 4px;
width: 32px;
align-items: center;
border-radius: var(--bn-border-radius-large);
cursor: pointer;
display: flex;
font-size: 24px;
height: 32px;
justify-content: center;
margin: 2px;
padding: 4px;
width: 32px;
}

.bn-ariakit .bn-grid-suggestion-menu-item[aria-selected="true"],
.bn-ariakit .bn-grid-suggestion-menu-item:hover {
background-color: var(--bn-colors-hovered-background);
background-color: var(--bn-colors-hovered-background);
}

.bn-ariakit .bn-grid-suggestion-menu-empty-item,
.bn-ariakit .bn-grid-suggestion-menu-loader {
align-items: center;
color: var(--bn-colors-menu-text);
display: flex;
font-size: 14px;
font-weight: 500;
height: 32px;
justify-content: center;
align-items: center;
color: var(--bn-colors-menu-text);
display: flex;
font-size: 14px;
font-weight: 500;
height: 32px;
justify-content: center;
}

.bn-ariakit .bn-grid-suggestion-menu-loader span {
background-color: var(--bn-colors-side-menu);
background-color: var(--bn-colors-side-menu);
}

.bn-ariakit .bn-side-menu {
align-items: center;
display: flex;
justify-content: center;
align-items: center;
display: flex;
justify-content: center;
}

.bn-side-menu .bn-ak-button {
height: fit-content;
padding: 0;
width: fit-content;
height: fit-content;
padding: 0;
width: fit-content;
}

.bn-ariakit .bn-panel-popover {
background-color: transparent;
border: none;
box-shadow: none;
background-color: transparent;
border: none;
box-shadow: none;
}

.bn-ariakit .bn-table-handle {
height: fit-content;
padding: 0;
width: fit-content;
height: fit-content;
padding: 0;
width: fit-content;
}

.bn-ariakit .bn-side-menu,
.bn-ariakit .bn-table-handle {
color: gray;
.bn-ariakit .bn-table-handle,
.bn-ariakit .bn-extend-button {
color: gray;
}

.bn-ariakit .bn-extend-button-editing {
background-color: hsl(204 4% 0% / 0.05);
}

.bn-ariakit .bn-extend-button-editing:where(.dark, .dark *) {
background-color: hsl(204 20% 100% / 0.05);
}

.bn-ariakit .bn-extend-button-add-remove-columns {
height: 100%;
width: 18px;
padding: 0;
margin-left: 4px;
cursor: col-resize;
}

.bn-ariakit .bn-extend-button-add-remove-rows {
height: 18px;
width: 100%;
padding: 0;
margin-top: 4px;
cursor: row-resize;
}

.bn-ak-button:where(.dark, .dark *) {
color: hsl(204 20% 100%);
color: hsl(204 20% 100%);
}

.bn-ak-tab,
.bn-ariakit .bn-file-input {
background-color: transparent;
color: black;
background-color: transparent;
color: black;
}

.bn-ak-tab:where(.dark, .dark *),
.bn-ariakit .bn-file-input:where(.dark, .dark *) {
color: white;
color: white;
}

.bn-ak-tooltip {
align-items: center;
display: flex;
flex-direction: column;
align-items: center;
display: flex;
flex-direction: column;
}
30 changes: 30 additions & 0 deletions packages/ariakit/src/tableHandle/ExtendButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Button as AriakitButton } from "@ariakit/react";

import { assertEmpty, mergeCSSClasses } from "@blocknote/core";
import { ComponentProps } from "@blocknote/react";
import { forwardRef } from "react";

export const ExtendButton = forwardRef<
HTMLButtonElement,
ComponentProps["TableHandle"]["ExtendButton"]
>((props, ref) => {
const { children, className, onMouseDown, onClick, ...rest } = props;

// false, because rest props can be added by mantine when button is used as a trigger
// assertEmpty in this case is only used at typescript level, not runtime level
assertEmpty(rest, false);

return (
<AriakitButton
className={mergeCSSClasses(
"bn-ak-button bn-ak-secondary",
className || ""
)}
ref={ref}
onMouseDown={onMouseDown}
onClick={onClick}
{...rest}>
{children}
</AriakitButton>
);
});
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"hast-util-from-dom": "^4.2.0",
"prosemirror-model": "^1.21.0",
"prosemirror-state": "^1.4.3",
"prosemirror-tables": "^1.3.7",
"prosemirror-tables": "^1.6.1",
"prosemirror-transform": "^1.9.0",
"prosemirror-view": "^1.33.7",
"rehype-format": "^5.0.0",
Expand Down
Loading

0 comments on commit a5e82dd

Please sign in to comment.