From 6a674fbc53c265e27b87f86e4db032433733f2f8 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Sep 2020 21:09:01 +0900 Subject: Introduce styled-components on form fields --- .../components/form/PartialBlacklistForm.tsx | 117 +++++++++++++-------- 1 file changed, 76 insertions(+), 41 deletions(-) (limited to 'src/settings/components/form/PartialBlacklistForm.tsx') diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index 95beee8..4c6bd35 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -1,9 +1,36 @@ -import "./PartialBlacklistForm.scss"; +import React from "react"; +import styled from "styled-components"; import AddButton from "../ui/AddButton"; import DeleteButton from "../ui/DeleteButton"; -import React from "react"; import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; +const Grid = styled.div``; + +const GridRow = styled.div` + display: flex; +`; + +const GridCell = styled.div<{ grow?: number }>` + &:nth-child(1) { + flex-grow: 5; + } + + &:nth-child(2) { + flex-shrink: 1; + min-width: 20%; + max-width: 20%; + } + + &:nth-child(3) { + flex-shrink: 1; + } +`; + +const Input = styled.input` + width: 100%; + box-sizing: border-box; +`; + interface Props { value: Blacklist; onChange: (value: Blacklist) => void; @@ -19,50 +46,58 @@ class PartialBlacklistForm extends React.Component { render() { return ( -
-
-
URL
-
Keys
-
- {this.props.value.items.map((item, index) => { - if (!item.partial) { - return null; - } - return ( -
- - - -
- ); - })} + <> + + + URL + Keys + + {this.props.value.items.map((item, index) => { + if (!item.partial) { + return null; + } + return ( + + + + + + + + + + + + ); + })} + -
+ ); } -- cgit v1.2.3 From e1e7c2d4d86d7aeb40357add27c76a99a18350e7 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Sep 2020 21:15:46 +0900 Subject: Introduce styled-components on top of form --- .../components/form/PartialBlacklistForm.tsx | 9 +- src/settings/components/form/SearchForm.tsx | 9 +- src/settings/components/index.tsx | 96 +++++++++++++--------- src/settings/components/site.scss | 21 ----- 4 files changed, 72 insertions(+), 63 deletions(-) delete mode 100644 src/settings/components/site.scss (limited to 'src/settings/components/form/PartialBlacklistForm.tsx') diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index 4c6bd35..dcdd00c 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -6,6 +6,11 @@ import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; const Grid = styled.div``; +const GridHeader = styled.div` + display: flex; + font-weight: bold; +`; + const GridRow = styled.div` display: flex; `; @@ -48,10 +53,10 @@ class PartialBlacklistForm extends React.Component { return ( <> - + URL Keys - + {this.props.value.items.map((item, index) => { if (!item.partial) { return null; diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index 3ba0299..cc7061a 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -6,6 +6,11 @@ import { FormSearch } from "../../../shared/SettingData"; const Grid = styled.div``; +const GridHeader = styled.div` + display: flex; + font-weight: bold; +`; + const GridRow = styled.div` display: flex; `; @@ -50,11 +55,11 @@ class SearchForm extends React.Component { return ( <> - + Name URL Default - + {value.engines.map((engine, index) => { return ( diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index d204210..2e2ff52 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -1,6 +1,6 @@ -import "./site.scss"; import React from "react"; import { connect } from "react-redux"; +import styled from "styled-components"; import TextArea from "./ui/TextArea"; import Radio from "./ui/Radio"; import SearchForm from "./form/SearchForm"; @@ -19,6 +19,28 @@ import { State as AppState } from "../reducers/setting"; import Properties from "../../shared/settings/Properties"; import Blacklist from "../../shared/settings/Blacklist"; +const Container = styled.form` + padding: 2px; + font-family: system-ui; +`; + +const Fieldset = styled.fieldset` + margin: 0; + padding: 0; + border: none; + margin-top: 1rem; + + &:first-of-type { + margin-top: 1rem; + } +`; + +const Legend = styled.legend` + font-size: 1.5rem; + padding: 0.5rem 0; + font-weight: bold; +`; + const DO_YOU_WANT_TO_CONTINUE = "Some settings in JSON can be lost when migrating. " + "Do you want to continue?"; @@ -41,47 +63,47 @@ class SettingsComponent extends React.Component { renderFormFields(form: FormSettings) { return (
-
- Keybindings +
+ Keybindings -
-
- Search Engines +
+
+ Search Engines -
-
- Blacklist +
+
+ Blacklist -
-
- Partial blacklist +
+
+ Partial blacklist -
-
- Properties +
+
+ Properties -
+
); } @@ -111,30 +133,28 @@ class SettingsComponent extends React.Component { fields = this.renderJsonFields(this.props.json!, this.props.error); } return ( -
+

Configure Vim-Vixen

-
- + - - {fields} - -
+ + {fields} + ); } diff --git a/src/settings/components/site.scss b/src/settings/components/site.scss deleted file mode 100644 index e8415e8..0000000 --- a/src/settings/components/site.scss +++ /dev/null @@ -1,21 +0,0 @@ -.vimvixen-settings-form { - padding: 2px; - font-family: system-ui; - - fieldset { - margin: 0; - padding: 0; - border: none; - margin-top: 1rem; - - fieldset:first-of-type { - margin-top: 1rem; - } - - legend { - font-size: 1.5rem; - padding: .5rem 0; - font-weight: bold; - } - } -} -- cgit v1.2.3 From 738a699259345e47a81cba8d14beb5b9fd2d8b53 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 22 Sep 2020 10:52:13 +0900 Subject: Fix e2e test on option --- e2e/lib/FormOptionPage.ts | 177 +++++++++++---------- e2e/lib/JSONOptionPage.ts | 4 +- src/settings/components/form/BlacklistForm.tsx | 3 + .../components/form/PartialBlacklistForm.tsx | 8 +- src/settings/components/form/SearchForm.tsx | 10 +- 5 files changed, 107 insertions(+), 95 deletions(-) (limited to 'src/settings/components/form/PartialBlacklistForm.tsx') diff --git a/e2e/lib/FormOptionPage.ts b/e2e/lib/FormOptionPage.ts index 5551684..666bac7 100644 --- a/e2e/lib/FormOptionPage.ts +++ b/e2e/lib/FormOptionPage.ts @@ -1,5 +1,5 @@ import { Lanthan } from "lanthan"; -import { WebDriver, By, until } from "selenium-webdriver"; +import { WebDriver, WebElement, By, error } from "selenium-webdriver"; export default class FormOptionPage { private webdriver: WebDriver; @@ -9,15 +9,15 @@ export default class FormOptionPage { } async setBlacklist(nth: number, url: string): Promise { - const selector = ".form-blacklist-form-row > .column-url"; - const inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a blacklist"); } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + + const input = rows[nth].findElement(By.css("[aria-label=URL]")); + await input.sendKeys(url); + await this.blurActiveElement(); } async setPartialBlacklist( @@ -25,121 +25,122 @@ export default class FormOptionPage { url: string, keys: string ): Promise { - let selector = ".form-partial-blacklist-form-row > .column-url"; - let inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a partial blacklist"); } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); - selector = ".form-partial-blacklist-form-row > .column-keys"; - inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { - throw new RangeError("Index out of range to set a partial blacklist"); - } - await inputs[nth].sendKeys(keys); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + const urlInput = rows[nth].findElement(By.css("[aria-label=URL]")); + await urlInput.sendKeys(url); + await this.blurActiveElement(); + + const keysInput = rows[nth].findElement(By.css("[aria-label=Keys]")); + await keysInput.sendKeys(keys); + await this.blurActiveElement(); } async setSearchEngine(nth: number, name: string, url: string) { - let selector = ".form-search-form-row > .column-name"; - let inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a search engine"); } - await inputs[nth].sendKeys(name); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); - selector = ".form-search-form-row > .column-url"; - inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { - throw new RangeError("Index out of range to set a search engine"); - } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + const nameInput = rows[nth].findElement(By.css("[aria-label=Name")); + await nameInput.sendKeys(name); + await this.blurActiveElement(); + + const urlInput = rows[nth].findElement(By.css("[aria-label=URL]")); + await urlInput.sendKeys(url); + await this.blurActiveElement(); } async addBlacklist(): Promise { - const rows = await this.webdriver.findElements( - By.css(`.form-blacklist-form-row`) - ); - const button = await this.webdriver.findElement( - By.css(".form-blacklist-form .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-blacklist-form-row:nth-child(${rows.length + 1})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async addPartialBlacklist(): Promise { - const rows = await this.webdriver.findElements( - By.css(`.form-partial-blacklist-form-row`) - ); - const button = await this.webdriver.findElement( - By.css(".form-partial-blacklist-form .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async removeBlackList(nth: number): Promise { - const buttons = await this.webdriver.findElements( - By.css(".form-blacklist-form-row .ui-delete-button") + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const deleteButtons = await fieldset.findElements( + By.css("[aria-label=Delete]") ); - if (buttons.length <= nth) { + if (deleteButtons.length <= nth) { throw new RangeError("Index out of range to remove blacklist"); } - await buttons[nth].click(); + await deleteButtons[nth].click(); } async removePartialBlackList(nth: number): Promise { - const buttons = await this.webdriver.findElements( - By.css(".form-partial-blacklist-form-row .ui-delete-button") - ); - if (buttons.length <= nth) { - throw new RangeError("Index out of range to remove partial blacklist"); + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const deleteButtons = await fieldset.findElements( + By.css("[aria-label=Delete]") + ); + if (deleteButtons.length <= nth) { + throw new RangeError( + `Index out of range ${deleteButtons.length} to remove partial blacklist ${nth}` + ); } - await buttons[nth].click(); + await deleteButtons[nth].click(); } async addSearchEngine(): Promise { - const rows = await this.webdriver.findElements( - By.css(`.form-search-form-row > .column-name`) - ); - const button = await this.webdriver.findElement( - By.css(".form-search-form > .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-search-form-row:nth-child(${rows.length + 1})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async setDefaultSearchEngine(nth: number): Promise { - const radios = await this.webdriver.findElements( - By.css(".form-search-form-row input[type=radio]") + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const radios = await fieldset.findElements( + By.css("[name=default][type=radio]") ); if (radios.length <= nth) { throw new RangeError("Index out of range to set a default search engine"); } await radios[nth].click(); } + + private async getFieldsetByLegend(legendText: string): Promise { + const fieldsets = await this.webdriver.findElements(By.tagName("fieldset")); + for (const fieldset of fieldsets) { + const legend = await fieldset.findElement(By.tagName("legend")); + if ((await legend.getText()) === legendText) { + return fieldset; + } + } + throw new error.NoSuchElementError( + `Unable to locate fieldset with legend: ` + legendText + ); + } + + private async blurActiveElement(): Promise { + await this.webdriver.executeScript(`document.activeElement.blur()`); + } } diff --git a/e2e/lib/JSONOptionPage.ts b/e2e/lib/JSONOptionPage.ts index 0f2b0a7..2d8147e 100644 --- a/e2e/lib/JSONOptionPage.ts +++ b/e2e/lib/JSONOptionPage.ts @@ -20,9 +20,7 @@ export default class JSONOptionPage { } async getErrorMessage(): Promise { - const error = await this.webdriver.findElement( - By.css(".settings-ui-input-error") - ); + const error = await this.webdriver.findElement(By.css("p[role=alert]")); return error.getText(); } } diff --git a/src/settings/components/form/BlacklistForm.tsx b/src/settings/components/form/BlacklistForm.tsx index d301f2c..6fb9eca 100644 --- a/src/settings/components/form/BlacklistForm.tsx +++ b/src/settings/components/form/BlacklistForm.tsx @@ -52,6 +52,7 @@ class BlacklistForm extends React.Component { data-index={index} type="text" name="url" + aria-label="URL" value={item.pattern} placeholder="example.com/mail/*" onChange={this.bindValue.bind(this)} @@ -64,6 +65,7 @@ class BlacklistForm extends React.Component { name="delete" onClick={this.bindValue.bind(this)} onBlur={this.props.onBlur} + aria-label="Delete" />
@@ -72,6 +74,7 @@ class BlacklistForm extends React.Component {
diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index dcdd00c..b2da2bb 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -52,7 +52,7 @@ class PartialBlacklistForm extends React.Component { render() { return ( <> - + URL Keys @@ -62,12 +62,13 @@ class PartialBlacklistForm extends React.Component { return null; } return ( - + { data-index={index} type="text" name="keys" + aria-label="Keys" value={item.keys.join(",")} placeholder="j,k,," onChange={this.bindValue.bind(this)} @@ -89,6 +91,7 @@ class PartialBlacklistForm extends React.Component { @@ -99,6 +102,7 @@ class PartialBlacklistForm extends React.Component { diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index cc7061a..4bf0e02 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -54,7 +54,7 @@ class SearchForm extends React.Component { const value = this.props.value.toJSON(); return ( <> - + Name URL @@ -62,12 +62,13 @@ class SearchForm extends React.Component { {value.engines.map((engine, index) => { return ( - + { data-index={index} type="text" name="url" + aria-label="URL" placeholder="http://example.com/?q={}" value={engine[1]} onChange={this.bindValue.bind(this)} @@ -89,11 +91,14 @@ class SearchForm extends React.Component { data-index={index} type="radio" name="default" + aria-label="Default" checked={value.default === engine[0]} onChange={this.bindValue.bind(this)} /> + a @@ -104,6 +109,7 @@ class SearchForm extends React.Component { -- cgit v1.2.3