Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(app): Align software keyboard with latest design #14700

Merged
merged 22 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import * as React from 'react'
import {
Flex,
DIRECTION_COLUMN,
Flex,
POSITION_ABSOLUTE,
SPACING,
VIEWPORT,
} from '@opentrons/components'
import { InputField } from '../../InputField'
import { CustomKeyboard } from './'
import { AlphanumericKeyboard } from '.'
import '../index.css'
import './index.css'

import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Atoms/SoftwareKeyboard/CustomKeyboard',
component: CustomKeyboard,
title: 'ODD/Atoms/SoftwareKeyboard/AlphanumericKeyboard',
component: AlphanumericKeyboard,
parameters: VIEWPORT.touchScreenViewport,
} as Meta

const Template: Story<React.ComponentProps<typeof CustomKeyboard>> = args => {
const Template: Story<
React.ComponentProps<typeof AlphanumericKeyboard>
> = args => {
const [showKeyboard, setShowKeyboard] = React.useState(false)
const [value, setValue] = React.useState<string>('')
const keyboardRef = React.useRef(null)
Expand All @@ -33,9 +35,9 @@ const Template: Story<React.ComponentProps<typeof CustomKeyboard>> = args => {
onFocus={() => setShowKeyboard(true)}
/>
</form>
<Flex position={POSITION_ABSOLUTE} top="20%" width="55rem">
<Flex position={POSITION_ABSOLUTE} top="20%" left="0" width="64rem">
{showKeyboard && (
<CustomKeyboard
<AlphanumericKeyboard
onChange={(e: string) => e != null && setValue(String(e))}
keyboardRef={keyboardRef}
/>
Expand All @@ -45,4 +47,4 @@ const Template: Story<React.ComponentProps<typeof CustomKeyboard>> = args => {
)
}

export const CustomSoftwareKeyboard = Template.bind({})
export const AlphanumericSoftwareKeyboard = Template.bind({})
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { describe, it, expect, vi } from 'vitest'
import '@testing-library/jest-dom/vitest'
import { fireEvent, renderHook, screen } from '@testing-library/react'
import { renderWithProviders } from '../../../../__testing-utils__'
import { CustomKeyboard } from '..'
import { AlphanumericKeyboard } from '..'

const render = (props: React.ComponentProps<typeof CustomKeyboard>) => {
return renderWithProviders(<CustomKeyboard {...props} />)[0]
const render = (props: React.ComponentProps<typeof AlphanumericKeyboard>) => {
return renderWithProviders(<AlphanumericKeyboard {...props} />)[0]
}

describe('CustomKeyboard', () => {
it('should render the custom keyboards lower case', () => {
describe('AlphanumericKeyboard', () => {
it('should render alphanumeric keyboard - lower case', () => {
const { result } = renderHook(() => React.useRef(null))
const props = {
onChange: vi.fn(),
Expand All @@ -29,6 +29,7 @@ describe('CustomKeyboard', () => {
'i',
'o',
'p',
'123',
'a',
's',
'd',
Expand All @@ -38,7 +39,7 @@ describe('CustomKeyboard', () => {
'j',
'k',
'l',
'SHIFT',
'ABC',
'z',
'x',
'c',
Expand All @@ -47,21 +48,20 @@ describe('CustomKeyboard', () => {
'n',
'm',
'del',
'123',
]
buttons.forEach((button, index) => {
const expectedName = expectedButtonNames[index]
expect(button).toHaveTextContent(expectedName)
})
})
it('should render the custom keyboards upper case, when clicking shift key', () => {
it('should render alphanumeric keyboard - upper case, when clicking ABC key', () => {
const { result } = renderHook(() => React.useRef(null))
const props = {
onChange: vi.fn(),
keyboardRef: result.current,
}
render(props)
const shiftKey = screen.getByRole('button', { name: 'SHIFT' })
const shiftKey = screen.getByRole('button', { name: 'ABC' })
fireEvent.click(shiftKey)

const buttons = screen.getAllByRole('button')
Expand All @@ -76,6 +76,7 @@ describe('CustomKeyboard', () => {
'I',
'O',
'P',
'123',
'A',
'S',
'D',
Expand All @@ -94,15 +95,14 @@ describe('CustomKeyboard', () => {
'N',
'M',
'del',
'123',
]
buttons.forEach((button, index) => {
const expectedName = expectedButtonNames[index]
expect(button).toHaveTextContent(expectedName)
})
})

it('should render the custom keyboards numbers, when clicking number key', () => {
it('should render alphanumeric keyboard - numbers, when clicking number key', () => {
const { result } = renderHook(() => React.useRef(null))
const props = {
onChange: vi.fn(),
Expand Down Expand Up @@ -132,17 +132,71 @@ describe('CustomKeyboard', () => {
})
})

it('should render the custom keyboards lower case, when clicking number key then abc key', () => {
it('should render alphanumeric keyboard - lower case when layout is numbers and clicking abc ', () => {
const { result } = renderHook(() => React.useRef(null))
const props = {
onChange: vi.fn(),
keyboardRef: result.current,
}
render(props)
const numberKey = screen.getByRole('button', { name: '123' })
screen.getByRole('button', { name: 'a' })
fireEvent.click(numberKey)
const abcKey = screen.getByRole('button', { name: 'abc' })
fireEvent.click(abcKey)
const buttons = screen.getAllByRole('button')
const expectedButtonNames = [
'q',
'w',
'e',
'r',
't',
'y',
'u',
'i',
'o',
'p',
'123',
'a',
's',
'd',
'f',
'g',
'h',
'j',
'k',
'l',
'ABC',
'z',
'x',
'c',
'v',
'b',
'n',
'm',
'del',
]
buttons.forEach((button, index) => {
const expectedName = expectedButtonNames[index]
expect(button).toHaveTextContent(expectedName)
})
})

it('should switch each alphanumeric keyboard properly', () => {
const { result } = renderHook(() => React.useRef(null))
const props = {
onChange: vi.fn(),
keyboardRef: result.current,
}
render(props)
// lower case keyboard -> upper case keyboard
const ABCKey = screen.getByRole('button', { name: 'ABC' })
fireEvent.click(ABCKey)
screen.getByRole('button', { name: 'A' })
// upper case keyboard -> number keyboard
const numberKey = screen.getByRole('button', { name: '123' })
fireEvent.click(numberKey)
screen.getByRole('button', { name: '1' })
// number keyboard -> lower case keyboard
const abcKey = screen.getByRole('button', { name: 'abc' })
fireEvent.click(abcKey)
screen.getByRole('button', { name: 'a' })
Expand Down
71 changes: 71 additions & 0 deletions app/src/atoms/SoftwareKeyboard/AlphanumericKeyboard/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* stylelint-disable */

/* Alphanumeric Keyboard has 3 layouts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

1. lower letter keys: hg-layout-default
2. upper letter keys: hg-layout-shift
3. number keys: hg-layout-numbers
1, 2 are using the same style but 3 has own style.
*/

.simple-keyboard.oddTheme1.hg-theme-default .hg-layout-default {
width: 100%;
height: 100%;
background-color: #cbcccc; /* grey35 */
font-family: 'Public Sans', sans-serif;
padding: 8px;
}

.hg-layout-default .hg-row .hg-button,
.hg-layout-shift .hg-row .hg-button,
.hg-layout-numbers .hg-row .hg-button {
color: #16212d;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 24px;
background-color: #ffffff;
padding: 10px 22px;
}

.simple-keyboard .hg-button:active {
color: #16212d;
background-color: #dedede; /* grey30 */
}

.hg-layout-default .hg-row .hg-button,
.hg-layout-shift .hg-row .hg-button {
height: 62.3px;
}

/* first row and second row */
.hg-layout-default .hg-row:not(:last-child),
.hg-layout-shift .hg-row:not(:last-child) {
grid-column: 8px;
}
.hg-row:not(:last-child) .hg-button {
width: 94px;
}

/* third row first button and last button are the same size
the rest is the same */
.hg-layout-default .hg-row:last-child,
.hg-layout-shift .hg-row:last-child,
.hg-layout-numbers .hg-row:last-child {
/* adding 3px because package's css add margin-right:5px */
grid-gap: 3px;
}
.hg-layout-default .hg-row:last-child .hg-button,
.hg-layout-shift .hg-row:last-child .hg-button {
width: 97px;
}
.hg-layout-default .hg-row:last-child .hg-button:first-child,
.hg-layout-default .hg-row:last-child .hg-button:last-child,
.hg-layout-shift .hg-row:last-child .hg-button:first-child,
.hg-layout-shift .hg-row:last-child .hg-button:last-child {
width: 132px;
}

.hg-layout-numbers .hg-row .hg-button {
height: 44.75px;
width: 330px !important;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does !important mean?

Copy link
Contributor Author

@koji koji Mar 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to override style. https://developer.mozilla.org/en-US/docs/Web/CSS/important
Generally, using important isn't good and I hate to use it since that makes CSS debug complicated.
I will keep an eye on this to solve important.

}
Original file line number Diff line number Diff line change
@@ -1,44 +1,36 @@
import * as React from 'react'
import Keyboard from 'react-simple-keyboard'
import { customDisplay } from '../constants'
import { alphanumericKeyboardLayout, customDisplay } from '../constants'

interface CustomKeyboardProps {
interface AlphanumericKeyboardProps {
onChange: (input: string) => void
keyboardRef: React.MutableRefObject<any>
}

const customLayout = {
default: [
'q w e r t y u i o p',
'a s d f g h j k l',
'{shift} z x c v b n m {backspace}',
'{numbers}',
],
shift: [
'Q W E R T Y U I O P',
'A S D F G H J K L',
'{abc} Z X C V B N M {backspace}',
'{numbers}',
],
numbers: ['1 2 3', '4 5 6', '7 8 9', '{abc} 0 {backspace}'],
}

export function CustomKeyboard({
export function AlphanumericKeyboard({
onChange,
keyboardRef,
}: CustomKeyboardProps): JSX.Element {
}: AlphanumericKeyboardProps): JSX.Element {
const [layoutName, setLayoutName] = React.useState<string>('default')
const onKeyPress = (button: string): void => {
if (button === '{shift}' || button === '{lock}') handleShift()
if (button === '{numbers}' || button === '{abc}') handleNumber()
console.log(button)
if (button === '{ABC}') handleShift()
if (button === '{numbers}') handleNumber()
if (button === '{abc}') handleUnShift()
}

const handleShift = (): void => {
setLayoutName(layoutName === 'default' ? 'shift' : 'default')
}

const handleNumber = (): void => {
setLayoutName(layoutName === 'default' ? 'numbers' : 'default')
setLayoutName(
layoutName === 'default' || layoutName === 'shift' ? 'numbers' : 'default'
)
}

const handleUnShift = (): void => {
setLayoutName('default')
}

return (
Expand All @@ -48,11 +40,12 @@ export function CustomKeyboard({
onChange={onChange}
onKeyPress={onKeyPress}
layoutName={layoutName}
layout={customLayout}
layout={alphanumericKeyboardLayout}
display={customDisplay}
mergeDisplay={true}
autoUseTouchEvents={true}
useButtonTag={true}
width="100%"
/>
)
}
33 changes: 0 additions & 33 deletions app/src/atoms/SoftwareKeyboard/CustomKeyboard/index.css

This file was deleted.

Loading
Loading