Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

#1422 Textarea enable linebreak (submitOnEnter) #1517

Merged
merged 6 commits into from
Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
@@ -0,0 +1,7 @@
Enhancement: OcTextarea configurable Enter/Linebreak

OcTextArea has now an property 'submitOnEnter'.
This prop controls how the textarea should react to ENTER.

https://github.com/owncloud/owncloud-design-system/issues/1422
https://github.com/owncloud/owncloud-design-system/pull/1517
133 changes: 133 additions & 0 deletions src/components/OcTextarea.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { shallowMount } from "@vue/test-utils"
import OcTextarea from "./OcTextarea.vue"

const defaultProps = {
label: "label",
}

describe("OcTextarea", () => {
function getShallowWrapper(props = {}) {
return shallowMount(OcTextarea, {
propsData: {
...defaultProps,
...props,
},
})
}

const selectors = {
textareaMessage: ".oc-textarea-message span",
textArea: ".oc-textarea",
}
describe("id prop", () => {
const wrapper = getShallowWrapper({
id: "test-textarea-id",
descriptionMessage: "hello",
})
it("should set provided id to the textarea", () => {
expect(wrapper.find("textarea").attributes().id).toBe("test-textarea-id")
})
it("should set label target for provided id", () => {
expect(wrapper.find("label").attributes().for).toBe("test-textarea-id")
})
it("should set message id according to provided id", () => {
expect(wrapper.find(selectors.textareaMessage).attributes().id).toBe(
"test-textarea-id-message"
)
})
})
describe("label prop", () => {
it("should set provided label to the textarea", () => {
const wrapper = getShallowWrapper()
expect(wrapper.find("label").text()).toBe("label")
})
})
describe("when a description message is provided", () => {
const wrapper = getShallowWrapper({ descriptionMessage: "You should pass." })
it("should add the description class to the textarea message", () => {
expect(wrapper.find(selectors.textareaMessage).attributes().class).toContain(
"oc-textarea-description"
)
})
it("should show the description message as the input message text", () => {
expect(wrapper.find(selectors.textareaMessage).text()).toBe("You should pass.")
})
})
describe("when a warning message is provided", () => {
const wrapper = getShallowWrapper({ warningMessage: "You may pass." })
it("should add the warning class to the textarea", () => {
expect(wrapper.find("textarea").attributes().class).toContain("oc-textarea-warning")
})
it("should add the warning class to the textarea message", () => {
expect(wrapper.find(selectors.textareaMessage).attributes().class).toContain(
"oc-textarea-warning"
)
})
it("should show the warning message as the textarea message text", () => {
expect(wrapper.find(selectors.textareaMessage).text()).toBe("You may pass.")
})
})
describe("when an error message is provided", () => {
const wrapper = getShallowWrapper({ errorMessage: "You shall not pass." })
it("should add the error class to the textarea", () => {
expect(wrapper.find("textarea").attributes().class).toContain("oc-textarea-danger")
})
it("should add the error class to the textarea message", () => {
expect(wrapper.find(selectors.textareaMessage).attributes().class).toContain(
"oc-textarea-danger"
)
})
it("should show the error message as the textarea message text", () => {
expect(wrapper.find(selectors.textareaMessage).text()).toBe("You shall not pass.")
})
it("should set the input aria-invalid attribute to true", () => {
expect(wrapper.find("textarea").attributes("aria-invalid")).toBe("true")
})
})
describe("message priority", () => {
it("should give error message top priority", () => {
const wrapper = getShallowWrapper({
errorMessage: "You shall not pass.",
warningMessage: "You may pass.",
descriptionMessage: "Your should pass.",
})
const messageEl = wrapper.find(".oc-textarea-message span")
expect(messageEl.attributes().class).toBe(
"oc-textarea-description oc-textarea-warning oc-textarea-danger"
)
expect(messageEl.text()).toBe("You shall not pass.")
})
it("should give warning message priority over description message", () => {
const wrapper = getShallowWrapper({
warningMessage: "You may pass.",
descriptionMessage: "Your should pass.",
})
const messageEl = wrapper.find(selectors.textareaMessage)
expect(messageEl.attributes().class).toBe("oc-textarea-description oc-textarea-warning")
expect(messageEl.text()).toBe("You may pass.")
})
})
describe("input events", () => {
it("should emit an input event on typing", async () => {
const wrapper = getShallowWrapper()
expect(wrapper.emitted().input).toBeFalsy()
await wrapper.find("textarea").setValue("a")
expect(wrapper.emitted().input).toBeTruthy()
expect(wrapper.emitted().input[0][0]).toBe("a")
})
})
describe("change events", () => {
it("should emit a change event if submitOnEnter is true", async () => {
const wrapper = getShallowWrapper({ submitOnEnter: true })
expect(wrapper.emitted().change).toBeFalsy()
await wrapper.find("textarea").trigger("keydown.enter")
expect(wrapper.emitted().change).toBeTruthy()
})
it("shouldn't emit a change event if submitOnEnter is false", async () => {
const wrapper = getShallowWrapper({ submitOnEnter: false })
expect(wrapper.emitted().change).toBeFalsy()
await wrapper.find("textarea").trigger("keydown.enter")
expect(wrapper.emitted().change).toBeFalsy()
})
})
})
16 changes: 14 additions & 2 deletions src/components/OcTextarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ export default {
type: Boolean,
default: false,
},
/**
* Configure if the value should be emitted on 'enter' or if it should do a linebreak
* if true: 'enter' emits value, ctrl + enter and shift + enter creates linebreak
* if false: 'enter' creates linebreak
*/
submitOnEnter: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
showMessageLine() {
Expand Down Expand Up @@ -158,9 +168,11 @@ export default {
this.$emit("focus", value)
},
onKeyDown(e) {
if (e.keyCode === 13) {
e.keyEnter = e.key === "Enter";
Copy link
Member

@kulmann kulmann Jul 22, 2021

Choose a reason for hiding this comment

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

Hm.... personally in favor of not altering the event. Since e.enterKey doesn't exist, you could just create a const and use it in the if statement, that still improves the readability a bit.
I.e. like this:

const enterKey = e.key === "Enter"
if (this.submitOnEnter && enterKey && !e.ctrlKey && !e.shiftKey) {

Copy link
Contributor Author

@lookacat lookacat Jul 22, 2021

Choose a reason for hiding this comment

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

looks fine to me ^^

if (this.submitOnEnter && e.keyEnter && !e.ctrlKey && !e.shiftKey) {
/**
* Change event - emitted as soon as the user hits enter
* Change event - emitted as soon as the user hits enter (without ctrl or shift)
* Only applies if submitOnEnter is set to true
* @type {string}
*/
this.$emit("change", e.target.value)
Expand Down