add 'width' option for Carbon container (#949)

* feat: add 'width' option for Carbon container

* feat: draggable width adjustment

* chore: auto disable widthAdjustment when edge starts dragging

* remove label width default; tweak settings style

* use only right width handler

* use react effects, add a11y role and props

* clean up code

* use clamp fn

* move max and min widths out of state

* give WidthHandler a display name

* tweak variable names

Co-authored-by: Mike Fix <mrfix84@gmail.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
main
aluc 5 years ago committed by GitHub
parent 249f94851d
commit 41722923d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,6 +11,7 @@ hljs.registerLanguage('javascript', javascript)
import SpinnerWrapper from './SpinnerWrapper' import SpinnerWrapper from './SpinnerWrapper'
import WindowControls from './WindowControls' import WindowControls from './WindowControls'
import WidthHandler from './WidthHandler'
import { import {
COLORS, COLORS,
@ -201,12 +202,19 @@ class Carbon extends React.PureComponent {
<div className="alpha eliminateOnRender" /> <div className="alpha eliminateOnRender" />
<div className="bg" /> <div className="bg" />
</div> </div>
<WidthHandler
innerRef={this.props.innerRef}
onChange={this.props.updateWidth}
paddingHorizontal={config.paddingHorizontal}
/>
<style jsx> <style jsx>
{` {`
.container { .container {
position: relative; position: relative;
min-width: ${config.widthAdjustment ? '90px' : '680px'}; min-width: ${config.widthAdjustment ? '90px' : 'auto'};
max-width: 1024px; max-width: ${config.widthAdjustment ? '1024px' : 'none'};
${config.widthAdjustment ? '' : `width: ${config.width}px;`}
padding: ${config.paddingVertical} ${config.paddingHorizontal}; padding: ${config.paddingVertical} ${config.paddingHorizontal};
} }
@ -236,13 +244,16 @@ class Carbon extends React.PureComponent {
} }
.container .bg { .container .bg {
${this.props.config.backgroundMode === 'image' ${
? `background: url(${backgroundImage}); this.props.config.backgroundMode === 'image'
? `background: url(${backgroundImage});
background-size: cover; background-size: cover;
background-repeat: no-repeat;` background-repeat: no-repeat;`
: `background: ${this.props.config.backgroundColor || config.backgroundColor}; : `background: ${this.props.config.backgroundColor || config.backgroundColor};
background-size: auto; background-size: auto;
background-repeat: repeat;`} position: absolute; background-repeat: repeat;`
}
position: absolute;
top: 0px; top: 0px;
right: 0px; right: 0px;
bottom: 0px; bottom: 0px;
@ -268,9 +279,11 @@ class Carbon extends React.PureComponent {
position: relative; position: relative;
z-index: 1; z-index: 1;
border-radius: 5px; border-radius: 5px;
${config.dropShadow ${
? `box-shadow: 0 ${config.dropShadowOffsetY} ${config.dropShadowBlurRadius} rgba(0, 0, 0, 0.55)` config.dropShadow
: ''}; ? `box-shadow: 0 ${config.dropShadowOffsetY} ${config.dropShadowBlurRadius} rgba(0, 0, 0, 0.55)`
: ''
};
} }
.container :global(.CodeMirror__container .CodeMirror) { .container :global(.CodeMirror__container .CodeMirror) {

@ -112,6 +112,7 @@ class Editor extends React.Component {
updateState = updates => this.setState(updates, () => this.onUpdate(this.state)) updateState = updates => this.setState(updates, () => this.onUpdate(this.state))
updateCode = code => this.updateState({ code }) updateCode = code => this.updateState({ code })
updateWidth = width => this.setState({ widthAdjustment: false, width })
async getCarbonImage( async getCarbonImage(
{ {
@ -438,6 +439,7 @@ class Editor extends React.Component {
ref={this.carbonNode} ref={this.carbonNode}
config={this.state} config={this.state}
onChange={this.updateCode} onChange={this.updateCode}
updateWidth={this.updateWidth}
loading={this.state.loading} loading={this.state.loading}
theme={theme} theme={theme}
> >

@ -11,7 +11,7 @@ import Popout, { managePopout } from './Popout'
import Button from './Button' import Button from './Button'
import Presets from './Presets' import Presets from './Presets'
import MenuButton from './MenuButton' import MenuButton from './MenuButton'
import { COLORS, DEFAULT_PRESETS, DEFAULT_SETTINGS } from '../lib/constants' import { COLORS, DEFAULT_PRESETS, DEFAULT_SETTINGS, DEFAULT_WIDTHS } from '../lib/constants'
import { toggle, getPresets, savePresets, generateId, fileToJSON } from '../lib/util' import { toggle, getPresets, savePresets, generateId, fileToJSON } from '../lib/util'
import SettingsIcon from './svg/Settings' import SettingsIcon from './svg/Settings'
@ -30,6 +30,7 @@ function WindowSettings({
dropShadowOffsetY, dropShadowOffsetY,
windowControls, windowControls,
widthAdjustment, widthAdjustment,
width,
watermark, watermark,
onWidthChanging, onWidthChanging,
onWidthChanged, onWidthChanged,
@ -80,9 +81,27 @@ function WindowSettings({
enabled={widthAdjustment} enabled={widthAdjustment}
onChange={onChange.bind(null, 'widthAdjustment')} onChange={onChange.bind(null, 'widthAdjustment')}
/> />
{!widthAdjustment && (
<div className="row settings-row width-row">
<Input
label="Width"
type="number"
value={width}
min={DEFAULT_WIDTHS.minWidth}
max={DEFAULT_WIDTHS.maxWidth}
onChange={e => onChange('width', e.target.value)}
width="50%"
/>
</div>
)}
<Toggle label="Watermark" enabled={watermark} onChange={onChange.bind(null, 'watermark')} /> <Toggle label="Watermark" enabled={watermark} onChange={onChange.bind(null, 'watermark')} />
<style jsx> <style jsx>
{` {`
.width-row {
justify-content: space-between;
padding: 8px 12px 8px 8px;
}
.row > :global(div:first-child) { .row > :global(div:first-child) {
border-right: 1px solid ${COLORS.SECONDARY}; border-right: 1px solid ${COLORS.SECONDARY};
} }
@ -353,6 +372,7 @@ class Settings extends React.PureComponent {
dropShadowOffsetY={this.props.dropShadowOffsetY} dropShadowOffsetY={this.props.dropShadowOffsetY}
windowControls={this.props.windowControls} windowControls={this.props.windowControls}
widthAdjustment={this.props.widthAdjustment} widthAdjustment={this.props.widthAdjustment}
width={this.props.width}
watermark={this.props.watermark} watermark={this.props.watermark}
/> />
) )

@ -0,0 +1,73 @@
import React from 'react'
import { DEFAULT_WIDTHS, COLORS } from '../lib/constants'
const { minWidth, maxWidth } = DEFAULT_WIDTHS
function clamp(value, min, max) {
if (value < min) {
return min
}
if (value > max) {
return max
}
return value
}
export default function WidthHandler(props) {
const { onChange, innerRef, paddingHorizontal } = props
const startX = React.useRef(null)
const startWidth = React.useRef(null)
React.useEffect(() => {
function handleMouseMove(e) {
if (!startX.current) return
const delta = e.pageX - startX.current // leftOrRight === 'left' ? startX - e.pageX : (startX - e.pageX) * -1
const calculated = startWidth.current + delta * window.devicePixelRatio
const newWidth = clamp(calculated, minWidth, maxWidth)
onChange(newWidth)
}
window.addEventListener('mousemove', handleMouseMove)
return () => window.removeEventListener('mousemove', handleMouseMove)
}, [innerRef, onChange])
return (
// eslint-disable-next-line
<div
className="handler"
onMouseDown={e => {
startX.current = e.pageX
startWidth.current = innerRef.current.clientWidth
}}
onMouseUp={() => {
startX.current = null
}}
role="separator"
aria-orientation="vertical"
aria-valuemin={minWidth}
aria-valuemax={maxWidth}
>
<style jsx>
{`
.handler {
z-index: 2;
position: absolute;
background-color: ${COLORS.BLUE};
top: ${paddingHorizontal};
bottom: ${paddingHorizontal};
right: ${paddingHorizontal};
width: 8px;
cursor: ew-resize;
opacity: 0;
}
.handler:hover {
opacity: 0.4;
}
`}
</style>
</div>
)
}

@ -1092,6 +1092,12 @@ export const DEFAULT_SETTINGS = {
squaredImage: false, squaredImage: false,
hiddenCharacters: false, hiddenCharacters: false,
name: '', name: '',
width: 680,
}
export const DEFAULT_WIDTHS = {
minWidth: 320,
maxWidth: 1280,
} }
export const DEFAULT_PRESETS = [ export const DEFAULT_PRESETS = [

Loading…
Cancel
Save