Mailspring/static/components/contenteditable.less

152 lines
3.9 KiB
Plaintext
Raw Normal View History

@import "ui-variables";
.contenteditable-container {
flex: 1;
display: flex;
line-height: 1.4;
position: relative;
color: @text-color;
font-size: @font-size;
div[contenteditable], .contenteditable {
flex: 1;
refactor(toolbar): allow toolbar extensions in contenteditable Summary: This is a refactor of the toolbar in the contenteditable. Goals of this are: 1. Allow developers to add new buttons to the toolbar 2. Allow developers to add other component types to the floating toolbar (like the LinkEditor) 3. Make the toolbar declaratively defined instead of imperatively set 4. Separate out logical units of the toolbar into individual sections 5. Clean up `innerState` of the Contenteditable The Floating Toolbar used to be an imperative mess. Doing simple functionality additions required re-understanding a very complex set of logic to hide and show the toolbar and delecately manage focus states. There also was no real capacity for any developer to extend the toolbar. It also used to be completely outside of our `atomicEdit` system and was a legacy of having raw access to contenteditable controls (since it all used to be directly inside of the contenteditable) Finally it was difficult to declaratively define things because the `innerState` of the Contenteditable was inconsistently used and its lifecycle not properly thought through. This fixed several lifecycle bugs with that. Along the way several of the DOMUtils methods were also subtly not functional and fixed. The Toolbar is now broken apart into separate logical units. There are now `ContentedtiableExtension`s that declare what should be displayed in the toolbar at any given moment. They define a method called `toolbarComponentData`. This is a pure function of the state of the `Contenteditable`. If selection and content conditions look correct, then that method will return a component to render. This is how we declaratively define whether a toolbar should be visible or not instead of manually setting `hide` & `show` bits. There is also a `toolbarButtons` method that declaratively defines buttons that can go in the new `<ToolbarButtons>` component. The `ToolbarButtonManager` takes care of extracting these and binding the correct editorAPI context. Now the `<LinkEditor>` is a separate component from the `<ToolbarButtons>` instead of being smashed together. The `LinkManager` takes care of declaring when the `LinkEditor` should be displayed and has properly bound methods to update the `contenteditable` through the standard `atomicEdit` interface. If users have additional contenteditable popup plugins (like displaying extra info on a name or some content in the composer), they can now implement the `toolbarComponentData` api and declaratively define that information based on the state of the contenteditable. Test Plan: TODO Reviewers: bengotow, juan Reviewed By: bengotow Differential Revision: https://phab.nylas.com/D2442
2016-01-21 06:35:20 +08:00
a:hover {
cursor: text;
}
}
spelling.misspelled {
background: linear-gradient(45deg, transparent, transparent 49%, red 49%, transparent 51%);
background-size: 2px 2px;
background-position: bottom;
background-repeat-y: no-repeat;
}
.floating-toolbar {
z-index: 10;
position: absolute;
background: #fff;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), inset 0 0 1px rgba(0,0,0,0.5);
border-radius: @border-radius-base;
color: @text-color;
transition-duration: .15s;
transition-property: opacity, margin;
refactor(toolbar): allow toolbar extensions in contenteditable Summary: This is a refactor of the toolbar in the contenteditable. Goals of this are: 1. Allow developers to add new buttons to the toolbar 2. Allow developers to add other component types to the floating toolbar (like the LinkEditor) 3. Make the toolbar declaratively defined instead of imperatively set 4. Separate out logical units of the toolbar into individual sections 5. Clean up `innerState` of the Contenteditable The Floating Toolbar used to be an imperative mess. Doing simple functionality additions required re-understanding a very complex set of logic to hide and show the toolbar and delecately manage focus states. There also was no real capacity for any developer to extend the toolbar. It also used to be completely outside of our `atomicEdit` system and was a legacy of having raw access to contenteditable controls (since it all used to be directly inside of the contenteditable) Finally it was difficult to declaratively define things because the `innerState` of the Contenteditable was inconsistently used and its lifecycle not properly thought through. This fixed several lifecycle bugs with that. Along the way several of the DOMUtils methods were also subtly not functional and fixed. The Toolbar is now broken apart into separate logical units. There are now `ContentedtiableExtension`s that declare what should be displayed in the toolbar at any given moment. They define a method called `toolbarComponentData`. This is a pure function of the state of the `Contenteditable`. If selection and content conditions look correct, then that method will return a component to render. This is how we declaratively define whether a toolbar should be visible or not instead of manually setting `hide` & `show` bits. There is also a `toolbarButtons` method that declaratively defines buttons that can go in the new `<ToolbarButtons>` component. The `ToolbarButtonManager` takes care of extracting these and binding the correct editorAPI context. Now the `<LinkEditor>` is a separate component from the `<ToolbarButtons>` instead of being smashed together. The `LinkManager` takes care of declaring when the `LinkEditor` should be displayed and has properly bound methods to update the `contenteditable` through the standard `atomicEdit` interface. If users have additional contenteditable popup plugins (like displaying extra info on a name or some content in the composer), they can now implement the `toolbarComponentData` api and declaratively define that information based on the state of the contenteditable. Test Plan: TODO Reviewers: bengotow, juan Reviewed By: bengotow Differential Revision: https://phab.nylas.com/D2442
2016-01-21 06:35:20 +08:00
margin-top: 0;
&.toolbar-visible {
opacity: 1;
visibility: visible;
margin-top: 0;
}
.toolbar-pointer {
position: absolute;
width: 22.5px;
height: 10px;
background: transparent url('images/tooltip/tooltip-bg-pointer@2x.png') no-repeat;
background-size: 22.5px 9.5px;
margin-left: -11.2px;
}
&.above {
.toolbar-pointer {
transform: rotate(0deg);
bottom: -9px;
}
}
&.below {
.toolbar-pointer {
transform: rotate(180deg);
top: -9px;
}
}
.floating-toolbar-input {
border: 0;
display: inline;
// The hardcoded numbers here represent the widths of the various
// icons and buttons that surround the input. They are hardcoded here
// because CSS does the calculation for us that we'd otherwise have to
// do in React before the element renders to the page.
width: calc(~"100% - 62px");
&.with-remove {
width: calc(~"100% - 95px");
}
color: @text-color;
}
@padding: 0.5em;
.btn {
background: transparent;
font-size: 16px;
height: auto;
border-radius: 0;
padding: @padding*0.75 @padding;
margin: 0;
color: @text-color;
box-shadow: none;
&:first-child {
padding-left: 1.5*@padding;
}
&:last-child {
padding-right: 1.5*@padding;
}
&:hover, &:active {
color: lighten(@text-color-link, 10%);
background: transparent;
}
}
.preview-btn-icon {
position: relative;
top: 1px;
padding: 0 @padding;
}
button.btn.toolbar-btn {
@padding-top: 4px;
@padding-left: 8px;
width: 12.5px + 2*@padding-left;
height: 12.5px + 2*@padding-top;
margin: 7.5px 0;
box-shadow: none;
border: 0;
border-right: 1px solid @border-color-divider;
&:last-child { border-right: 0 }
background: no-repeat;
background-size: 12.5px 12.5px;
background-position: @padding-left @padding-top;
&.btn-bold { background-image: url("images/composer/tooltip-bold-black@2x.png") }
&.btn-italic { background-image: url("images/composer/tooltip-italic-black@2x.png") }
&.btn-underline { background-image: url("images/composer/tooltip-underline-black@2x.png") }
&.btn-link { background-image: url("images/composer/tooltip-link-black@2x.png") }
&:hover {
cursor: pointer;
background: no-repeat;
background-size: 12.5px 12.5px;
background-position: @padding-left @padding-top;
&.btn-bold { background-image: url("images/composer/tooltip-bold-blue@2x.png") }
&.btn-italic { background-image: url("images/composer/tooltip-italic-blue@2x.png") }
&.btn-underline { background-image: url("images/composer/tooltip-underline-blue@2x.png") }
&.btn-link { background-image: url("images/composer/tooltip-link-blue@2x.png") }
}
}
}
}
body.platform-win32 {
.contenteditable-container {
.floating-toolbar {
border-radius: 0;
input, input:focus {
border: 0;
}
}
}
}