Text-input / v-input fixes (#386)

* textinput fixes including masking trimming icons and fonts

* removed masked attribute from v-input

* added wrapper div

* ugh

* test fix

* fixed all calls to monospace boolean except on textarea (in separate branch)

* readonly

* Remove unused wrapper div and rename readonly to disabled

* Rename readonly to disabled in story

* Prefer style over inline styles

* Fix codesmell

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
Jacob Rienstra
2020-04-20 10:23:01 -04:00
committed by GitHub
parent 471c759df7
commit bf79610219
18 changed files with 248 additions and 102 deletions

View File

@@ -43,7 +43,7 @@ export const collection = () =>
hidden_browse: false,
required: false,
options: {
monospace: true,
font: 'monospace',
},
locked: false,
translation: null,

View File

@@ -13,30 +13,33 @@ The HTML `<input>` element supports a huge amount of attributes and events. In o
You can add any custom (text) prefix/suffix to the value in the input using the `prefix` and `suffix` slots.
## Props
| Prop | Description | Default |
|------------------|------------------------------------------------|---------|
| `autofocus` | Autofocusses the input on render | `false` |
| `disabled` | Set the disabled state for the input | `false` |
| `monospace` | Render the entered value in the monospace font | `false` |
| `full-width` | Render the input with 100% width | `false` |
| `prefix` | Prefix the users value with a value | -- |
| `suffix` | Show a value at the end of the input | -- |
| `slug` | Force the value to be URL safe | `false` |
| `slug-separator` | What character to use as separator in slugs | `-` |
| Prop | Description | Default |
| ---------------- | ------------------------------------------- | ------- |
| `autofocus` | Autofocusses the input on render | `false` |
| `disabled` | Set the disabled state for the input | `false` |
| `full-width` | Render the input with 100% width | `false` |
| `prefix` | Prefix the users value with a value | -- |
| `suffix` | Show a value at the end of the input | -- |
| `slug` | Force the value to be URL safe | `false` |
| `slug-separator` | What character to use as separator in slugs | `-` |
| `trim` | Trim leading and trailing whitespace | `true` |
Note: all other attached attributes are bound to the input HTMLELement in the component. This allows you to attach any of the standard HTML attributes like `min`, `length`, or `pattern`.
## Slots
| Slot | Description | Data |
|-----------------|---------------------------------------------------|--------------------------------------------------|
| --------------- | ------------------------------------------------- | ------------------------------------------------ |
| `prepend-outer` | Before the input | `{ disabled: boolean, value: string | number; }` |
| `prepend` | In the input, before the value, before the prefix | `{ disabled: boolean, value: string | number; }` |
| `append` | In the input, after the value, after the suffix | `{ disabled: boolean, value: string | number; }` |
| `append-outer` | After the input | `{ disabled: boolean, value: string | number; }` |
## Events
| Events | Description | Value |
|-----------------------|----------------------------------------------|-------|
| --------------------- | -------------------------------------------- | ----- |
| `input` | Updates `v-model` | `any` |
| `click:append` | User clicks on content of inner append slot | -- |
| `click:prepend` | User clicks on content of inner prepend slot | -- |
@@ -46,4 +49,7 @@ Note: all other attached attributes are bound to the input HTMLELement in the co
Note: all other listeners are bound to the input HTMLElement, allowing you to handle everything from `keydown` to `emptied`.
## CSS Variables
n/a
| Variable | Default |
| ----------------------- | -------------------------- |
| `--v-input-font-family` | `var(--family-sans-serif)` |

View File

@@ -1,4 +1,4 @@
import { withKnobs, text } from '@storybook/addon-knobs';
import { withKnobs, text, boolean } from '@storybook/addon-knobs';
import Vue from 'vue';
import VInput from './v-input.vue';
import markdown from './readme.md';
@@ -22,13 +22,21 @@ export default {
export const basic = () =>
defineComponent({
components: { RawValue },
props: {
placeholder: {
default: text('Placeholder', 'Enter a value...', 'Options'),
},
trim: {
default: boolean('Trim', false, 'Options'),
},
},
setup() {
const value = ref(null);
return { value };
},
template: `
<div>
<v-input v-model="value" placeholder="Enter content..." />
<v-input v-model="value" v-bind="{placeholder, trim}" />
<raw-value>{{ value }}</raw-value>
</div>
`,
@@ -42,7 +50,7 @@ export const monospace = () => ({
},
template: `
<div>
<v-input v-model="value" placeholder="Enter content..." monospace />
<v-input v-model="value" placeholder="Enter content..." :style="{'--v-input-font-family': 'var(--family-monospace)'}" />
</div>
`,
});

View File

@@ -54,12 +54,11 @@ describe('Input', () => {
it('Sets the correct classes based on props', async () => {
component.setProps({
disabled: true,
monospace: true,
});
await component.vm.$nextTick();
expect(component.find('.input').classes()).toEqual(['input', 'disabled', 'monospace']);
expect(component.find('.input').classes()).toEqual(['input', 'disabled']);
});
it('Emits just the value for the input event', async () => {

View File

@@ -1,3 +1,4 @@
f
<template>
<div
class="v-input"
@@ -7,7 +8,7 @@
<div v-if="$slots['prepend-outer']" class="prepend-outer">
<slot name="prepend-outer" :value="value" :disabled="disabled" />
</div>
<div class="input" :class="{ disabled, monospace }">
<div class="input" :class="{ disabled }">
<div v-if="$slots.prepend" class="prepend">
<slot name="prepend" :value="value" :disabled="disabled" />
</div>
@@ -53,10 +54,6 @@ export default defineComponent({
type: String,
default: null,
},
monospace: {
type: Boolean,
default: false,
},
fullWidth: {
type: Boolean,
default: false,
@@ -73,6 +70,10 @@ export default defineComponent({
type: String,
default: '-',
},
trim: {
type: Boolean,
default: true,
},
},
setup(props, { emit, listeners }) {
const _listeners = computed(() => ({
@@ -91,6 +92,8 @@ export default defineComponent({
if (props.slug === true) {
value = slugify(value, { separator: props.slugSeparator });
} else if (props.trim === true) {
value = value.trim();
}
emit('input', value);
@@ -101,6 +104,8 @@ export default defineComponent({
<style lang="scss" scoped>
.v-input {
--v-input-font-family: var(--family-sans-serif);
display: flex;
align-items: center;
width: max-content;
@@ -117,6 +122,7 @@ export default defineComponent({
height: 100%;
padding: var(--input-padding);
color: var(--foreground-normal);
font-family: var(--v-input-font-family);
background-color: var(--background-page);
border: var(--border-width) solid var(--border-normal);
border-radius: var(--border-radius);
@@ -158,6 +164,7 @@ export default defineComponent({
flex-grow: 1;
width: 100px; // allows flex to shrink to allow for slots
height: 100%;
font-family: var(--v-input-font-family);
background-color: transparent;
border: none;
appearance: none;
@@ -167,29 +174,6 @@ export default defineComponent({
}
}
&.has-click {
cursor: pointer;
input {
pointer-events: none;
}
}
&.active .input {
color: var(--foreground-normal);
background-color: var(--background-page);
border-color: var(--primary);
}
.input.monospace {
input {
font-family: var(--family-monospace);
}
}
.append-outer {
margin-left: 8px;
}
&.full-width {
width: 100%;
@@ -197,5 +181,26 @@ export default defineComponent({
width: 100%;
}
}
&.has-click {
cursor: pointer;
input {
pointer-events: none;
.prefix,
.suffix {
color: var(--foreground-subdued);
}
}
&.active .input {
color: var(--foreground-normal);
background-color: var(--background-page);
border-color: var(--primary);
}
.append-outer {
margin-left: 8px;
}
}
}
</style>

View File

@@ -23,25 +23,29 @@ Renders a dropdown input.
## Props
| Prop | Description | Default |
|---------------|-----------------------------------------------------|---------|
| `items`* | Items to render in the select | |
| ------------- | --------------------------------------------------- | ------- |
| `items`\* | Items to render in the select | |
| `itemText` | What item value to use for the display text | `text` |
| `itemValue` | What item value to use for the item value | `value` |
| `value` | Currently selected item(s) | |
| `multiple` | Allow multiple items to be selected | `false` |
| `placeholder` | What placeholder to show when no items are selected | |
| `full-width` | Render the select at full width | |
| `monospace` | Render the value and options monospaced | |
| `disabled` | Disable the select | |
## Events
| Event | Description | Value |
|---------|--------------------------|-----------------------------------------|
| ------- | ------------------------ | --------------------------------------- |
| `input` | New value for the select | `(string | number)[] | string | number` |
## Slots
n/a
## CSS Variables
n/a
| Variable | Default |
| ------------------------ | -------------------------- |
| `--v-select-font-family` | `var(--family-sans-serif)` |

View File

@@ -8,7 +8,6 @@
<template #activator="{ toggle }">
<v-input
:full-width="fullWidth"
:monospace="monospace"
readonly
:value="displayValue"
@click="toggle"
@@ -29,7 +28,7 @@
@click="multiple ? null : $emit('input', item.value)"
>
<v-list-item-content>
<span v-if="multiple === false" :class="{ monospace }">{{ item.text }}</span>
<span v-if="multiple === false" class="item-text">{{ item.text }}</span>
<v-checkbox
v-else
:inputValue="value || []"
@@ -86,10 +85,6 @@ export default defineComponent({
type: Boolean,
default: false,
},
monospace: {
type: Boolean,
default: false,
},
allowNull: {
type: Boolean,
default: false,
@@ -147,15 +142,23 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.monospace {
font-family: var(--family-monospace);
}
.v-select {
--v-select-font-family: var(--family-sans-serif);
.v-input {
cursor: pointer;
font-family: var(--v-select-font-family);
.item-text {
font-family: var(--v-select-font-family);
}
.v-input {
--v-input-font-family: var(--v-select-font-family);
::v-deep input {
cursor: pointer;
::v-deep input {
cursor: pointer;
}
}
}
</style>