Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
feat(editable-title): make page title editable (#553)
Browse files Browse the repository at this point in the history
* feat(chrome-name): component prep for the new editable title

* feat(chrome-title): include interaction handlers

* feat(editable-title): extract component from preview tile

* feat(editable-title-component): implementation and integration

* feat(editable-title): implementation of the editable title container

* chore(general): fix lint errors from origin

* fix(editable-title): rename the state enum

:

* fix(editable-title): include data-attr directly during rendering

* chore(editable-tigle): rename the editable-title-state enum

* fix(editable-title): remove fontSize props

* feat(editable title): include title type enumerable

* chore(editable-title): extract dinamic styled into own functions

* chore(page-tile): remove unnecessary HTML and styling

* fix(editable-title): remove text truncation on input (edit mode)

* fix(editable-container): move global state into an internal state

* fix: allow primary and secondary type

* fix(editable-title): include required category property

* chore(types): include editable title type in the model types
  • Loading branch information
Palmaswell authored Jun 25, 2018
1 parent 42da585 commit 6834f09
Show file tree
Hide file tree
Showing 15 changed files with 474 additions and 247 deletions.
11 changes: 7 additions & 4 deletions src/components/chrome/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ const DemoChrome: React.StatelessComponent<void> = () => (
<DemoContainer title="Chrome">
<Chrome>
<ViewSwitch
fontSize={CopySize.M}
onLeftClick={() => null}
onRightClick={() => null}
leftVisible={true}
rightVisible={true}
title="Page Title"
/>
>
Page Name
</ViewSwitch>
<ViewSwitch
fontSize={CopySize.M}
onLeftClick={() => null}
onRightClick={() => null}
leftVisible={true}
rightVisible={true}
title="Page Title"
/>
>
Page Name
</ViewSwitch>
</Chrome>
<IconRegistry />
</DemoContainer>
Expand Down
31 changes: 31 additions & 0 deletions src/components/editable-title/demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';

import DemoContainer from '../demo-container';
import { Headline } from '../headline';
import { Space, SpaceSize } from '../space';
import { EditableTitle, EditableTitleState, EditableTitleType } from '.';

export default (): JSX.Element => (
<DemoContainer title="Preview Tile">
<Space size={[SpaceSize.L, SpaceSize.XXXL]}>
<Headline order={2}>Editable Title</Headline>
<EditableTitle
focused={true}
name="Well crafted title"
nameState={EditableTitleState.Editable}
category={EditableTitleType.Primary}
value="Well crafted title"
/>
</Space>
<Space size={[SpaceSize.L, SpaceSize.XXXL]}>
<Headline order={2}>Editable Title</Headline>
<EditableTitle
focused={true}
name="Well crafted title"
nameState={EditableTitleState.Editable}
category={EditableTitleType.Secondary}
value="Well crafted title"
/>
</Space>
</DemoContainer>
);
176 changes: 176 additions & 0 deletions src/components/editable-title/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import styled from 'styled-components';

import { Color } from '../colors';
import { CopySize } from '../copy';
import { getSpace, SpaceSize } from '../space';

export enum EditableTitleState {
Editable = 'Editable',
Editing = 'Editing'
}

export enum EditableTitleType {
Primary,
Secondary
}

export interface EditableTitleProps {
category: EditableTitleType;
focused: boolean;
name: string;
nameState: EditableTitleState;
value: string;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onClick?: React.MouseEventHandler<HTMLElement>;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
}

interface EditableInputProps {
category: EditableTitleType;
autoFocus: boolean;
autoSelect: boolean;
value: string;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onClick?: React.MouseEventHandler<HTMLElement>;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
}

interface StyledEditableTitleProps {
children: React.ReactNode;
editable: boolean;
focused?: boolean;
category: EditableTitleType;
}

interface StyledInputProps {
category: EditableTitleType;
}

const categorizedTitleStyles = (props: StyledEditableTitleProps) => {
switch (props.category) {
case EditableTitleType.Secondary:
return `
width: 200px;
margin: 0 ${getSpace(SpaceSize.XS)}px ${getSpace(SpaceSize.XXS)}px;
font-size: ${CopySize.M}px;
color: ${Color.Grey36};
`;
case EditableTitleType.Primary:
default:
return `
width: 100%;
margin: 0;
font-size: ${CopySize.S}px;
color: ${Color.Black};
`;
}
};

const StyledTitle = styled.strong`
box-sizing: border-box;
display: inline-block;
padding: 0;
overflow: hidden;
font-weight: normal;
text-align: center;
cursor: ${(props: StyledEditableTitleProps) => (props.editable ? 'text' : 'default')};
white-space: nowrap;
text-overflow: ellipsis;
${categorizedTitleStyles};
`;

const categorizedEditableTitleStyles = (props: StyledInputProps) => {
switch (props.category) {
case EditableTitleType.Secondary:
return `
width: 200px;
margin: 0 ${getSpace(SpaceSize.XS)}px ${getSpace(SpaceSize.XXS)}px;
font-size: ${CopySize.M}px;
`;
case EditableTitleType.Primary:
default:
return `
width: 100%;
margin: 0;
font-size: ${CopySize.S}px;
`;
}
};

const StyledEditableTitle = styled.input`
box-sizing: border-box;
display: inline-block;
border: 0;
padding: 0;
overflow: hidden;
text-align: center;
${categorizedEditableTitleStyles} :focus {
outline: none;
}
`;

class EditableInput extends React.Component<EditableInputProps> {
public componentDidMount(): void {
const node = ReactDOM.findDOMNode(this);
if (!node) {
return;
}
const element = node as HTMLInputElement;

if (this.props.autoSelect) {
element.setSelectionRange(0, this.props.value.length);
}
}

public render(): JSX.Element {
const { props } = this;
return (
<StyledEditableTitle
autoFocus
data-title={true}
onBlur={props.onBlur}
onChange={props.onChange}
onFocus={props.onFocus}
onKeyDown={props.onKeyDown}
category={props.category}
value={props.value}
/>
);
}
}

export const EditableTitle: React.SFC<EditableTitleProps> = (props): JSX.Element => (
<React.Fragment>
{props.nameState === EditableTitleState.Editing ? (
<EditableInput
autoFocus
autoSelect
category={props.category}
data-title={true}
onBlur={props.onBlur}
onClick={props.onClick}
onChange={props.onChange}
onFocus={props.onFocus}
onKeyDown={props.onKeyDown}
value={props.name}
/>
) : (
<StyledTitle
category={props.category}
data-title={true}
editable={props.focused}
onClick={props.onClick}
>
{props.name}
</StyledTitle>
)}
</React.Fragment>
);
7 changes: 7 additions & 0 deletions src/components/editable-title/pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "editable-tile",
"displayName": "Editable Tile",
"flag": "alpha",
"version": "1.0.0",
"tags": ["atom"]
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './chrome';
export * from './colors';
export * from './copy';
export * from './create-select';
export * from './editable-title';
export * from './element';
export * from './element-slot';
export * from './fonts';
Expand Down
32 changes: 4 additions & 28 deletions src/components/page-tile/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import DemoContainer from '../demo-container';
import { Headline } from '../headline';
import { Layout } from '../layout';
import { Space, SpaceSize } from '../space';
import { EditState, PageTile } from '.';
import { PageTile } from '.';

const handleChange = (e: React.ChangeEvent<HTMLInputElement>): string => e.target.value;

Expand All @@ -26,44 +26,20 @@ export default (): JSX.Element => (
focused={false}
highlighted={false}
onChange={handleChange}
name="Editable"
nameState={EditState.Editable}
/>
</Space>
<Space size={SpaceSize.S}>
<PageTile
focused={true}
highlighted={false}
onChange={handleChange}
name="Page Name"
nameState={EditState.Editable}
/>
</Space>
<Space size={SpaceSize.S}>
<PageTile
focused={true}
highlighted={false}
onChange={handleChange}
name="Editable Page Name"
nameState={EditState.Editable}
/>
</Space>
<Space size={SpaceSize.S}>
<PageTile
focused={false}
highlighted={false}
highlighted={true}
onChange={handleChange}
name="Editable Page Name"
nameState={EditState.Editable}
/>
</Space>
<Space size={SpaceSize.S}>
<PageTile
focused={false}
highlighted={false}
focused={true}
highlighted={true}
onChange={handleChange}
name="Editable Page Name"
nameState={EditState.Editable}
/>
</Space>
</Layout>
Expand Down
Loading

0 comments on commit 6834f09

Please sign in to comment.