Skip to content
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
57 changes: 57 additions & 0 deletions src/assets/input-border.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

/**
* Similar as inputBorder but without active styles.
*/
@mixin inputLikeBorder($legacySelector, $borderColor: var(--color-border-maxcontrast)) {
--input-border-box-shadow-light: 0 -1px #{$borderColor},
0 0 0 1px color-mix(in srgb, #{$borderColor}, 65% transparent);
--input-border-box-shadow-dark: 0 1px #{$borderColor},
0 0 0 1px color-mix(in srgb, #{$borderColor}, 65% transparent);
--input-border-box-shadow: var(--input-border-box-shadow-light);
border: none;
border-radius: var(--border-radius-element);
box-shadow: var(--input-border-box-shadow);

&:hover:not([disabled]) {
box-shadow: 0 0 0 1px $borderColor;
}

// override with system theme
@media (prefers-color-scheme: dark) {
--input-border-box-shadow: var(--input-border-box-shadow-dark);
}

// override with nextcloud theme
@at-root [data-theme-dark] #{&} {
--input-border-box-shadow: var(--input-border-box-shadow-dark);
}
@at-root [data-theme-light] #{&} {
--input-border-box-shadow: var(--input-border-box-shadow-light);
}

@at-root #{$legacySelector} #{&} {
box-shadow: 0 0 0 1px $borderColor;

&:hover:not([disabled]) {
box-shadow: 0 0 0 2px $borderColor;
}
}
}

/**
* Create a consistent border for an input element.
* With Nextcloud 32+ there is no real border anymore but we use a box-shadow.
*/
@mixin inputBorder($legacySelector, $borderColor: var(--color-border-maxcontrast)) {
@include inputLikeBorder($legacySelector, $borderColor);

&:focus-within:not([disabled]),
&:active:not([disabled]) {
box-shadow: 0 0 0 2px $borderColor,
0 0 0 4px var(--color-main-background) !important;
}
}
48 changes: 7 additions & 41 deletions src/components/NcInputField/NcInputField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ For a list of all available props and attributes, please check the [HTMLInputEle
<script>
import AlertCircle from 'vue-material-design-icons/AlertCircleOutline.vue'
import Check from 'vue-material-design-icons/Check.vue'
import NcButton from '../NcButton/NcButton.vue'
import { useModelMigration } from '../../composables/useModelMigration.ts'
import GenRandomId from '../../utils/GenRandomId.js'
import { isLegacy32 } from '../../utils/legacy.ts'
import { logger } from '../../utils/logger.ts'
import NcButton from '../NcButton/index.js'

export default {
name: 'NcInputField',
Expand Down Expand Up @@ -286,6 +286,7 @@ export default {

setup() {
const model = useModelMigration('value', 'update:value', true)

return {
isLegacy32,
model,
Expand Down Expand Up @@ -369,12 +370,11 @@ export default {
</script>

<style lang="scss" scoped>
@use '../../assets/input-border.scss' as border;

.input-field {
--input-border-color: var(--color-border-maxcontrast);
--input-border-radius: var(--border-radius-element);
// Used e.g. if border width differs between focused and unfocused we need to compensate to prevent jumping
--input-border-width-offset: calc(var(--border-width-input-focused, 2px) - var(--border-width-input, 2px));
// The padding before the input can start (leading button or border)
--input-padding-start: var(--border-radius-large);
// The padding where the input has to end (trailing button or border)
Expand Down Expand Up @@ -408,23 +408,15 @@ export default {

&__main-wrapper {
height: var(--default-clickable-area);
padding: var(--border-width-input, 2px);
padding: var(--border-width-input-focused, 2px);
position: relative;

&:not(:has([disabled])):has(input:focus),
&:not(:has([disabled])):has(input:active) {
padding: 0;
}
}

&__input {
@include border.inputBorder('.input-field--legacy', var(--input-border-color));
background-color: var(--color-main-background);
color: var(--color-main-text);
border: none;
border-radius: var(--input-border-radius);
box-shadow:
0 -1px var(--input-border-color),
0 0 0 1px color-mix(in srgb, var(--input-border-color), 65% transparent);

cursor: pointer;
-webkit-appearance: textfield !important;
Expand All @@ -434,11 +426,11 @@ export default {
font-size: var(--default-font-size);
text-overflow: ellipsis;

padding-block: 0;
padding-inline: var(--input-padding-start) var(--input-padding-end);
height: 100% !important;
min-height: unset;
width: 100%;
padding-block: var(--input-border-width-offset);
padding-inline: calc(var(--input-padding-start) + var(--input-border-width-offset)) calc(var(--input-padding-end) + var(--input-border-width-offset));

&::placeholder {
color: var(--color-text-maxcontrast);
Expand All @@ -458,17 +450,9 @@ export default {
display: none;
}

&:hover:not([disabled]) {
box-shadow: 0 0 0 1px var(--input-border-color);;
}

&:active:not([disabled]),
&:focus:not([disabled]) {
--input-border-color: var(--color-main-text);
// Reset padding offset when focused
--input-border-width-offset: 0px;
border: var(--border-width-input-focused, 2px) solid var(--input-border-color);
box-shadow: 0 0 0 2px var(--color-main-background) !important;
}

&:focus + .input-field__label,
Expand Down Expand Up @@ -611,23 +595,5 @@ export default {
}
}
}

&--legacy {
.input-field__input {
box-shadow: 0 0 0 1px var(--input-border-color) inset;
}

.input-field__main-wrapper:hover:not(:has([disabled])) {
padding: 0;

.input-field__input {
--input-border-color: var(--color-main-text);
// Reset padding offset when focused
--input-border-width-offset: 0px;
border: var(--border-width-input-focused, 2px) solid var(--input-border-color);
box-shadow: 0 0 0 2px var(--color-main-background) !important;
}
}
}
}
</style>
38 changes: 27 additions & 11 deletions src/components/NcSelect/NcSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export default {
<VueSelect
class="select"
:class="{
'select--legacy': isLegacy,
'select--no-wrap': noWrap,
'user-select': userSelect,
}"
Expand Down Expand Up @@ -414,12 +415,13 @@ import { VueSelect } from '@nextcloud/vue-select'
import Vue from 'vue'
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
import Close from 'vue-material-design-icons/Close.vue'
import NcEllipsisedOption from '../NcEllipsisedOption/NcEllipsisedOption.vue'
import NcListItemIcon from '../NcListItemIcon/NcListItemIcon.vue'
import NcLoadingIcon from '../NcLoadingIcon/NcLoadingIcon.vue'
import { useModelMigration } from '../../composables/useModelMigration.ts'
import { t } from '../../l10n.js'
import GenRandomId from '../../utils/GenRandomId.js'
import NcEllipsisedOption from '../NcEllipsisedOption/index.js'
import NcListItemIcon from '../NcListItemIcon/index.js'
import NcLoadingIcon from '../NcLoadingIcon/index.js'
import { isLegacy32 as isLegacy } from '../../utils/legacy.ts'

import '@nextcloud/vue-select/dist/vue-select.css'

Expand Down Expand Up @@ -860,6 +862,7 @@ export default {
return {
avatarSize,
model,
isLegacy,
}
},

Expand Down Expand Up @@ -1013,6 +1016,8 @@ export default {
</script>

<style lang="scss">
@use '../../assets/input-border.scss' as border;

body {
/**
* Set custom vue-select CSS variables.
Expand Down Expand Up @@ -1082,7 +1087,7 @@ body {

.v-select.select {
/* Override default vue-select styles */
min-height: var(--default-clickable-area);
min-height: calc(var(--default-clickable-area) - 2 * var(--border-width-input));
min-width: 260px;
margin: 0 0 var(--default-grid-baseline);

Expand Down Expand Up @@ -1127,7 +1132,7 @@ body {
.vs__dropdown-toggle {
position: relative;
max-height: 100px;
padding: 0;
padding: var(--border-width-input);
overflow-y: auto;
}

Expand All @@ -1141,15 +1146,22 @@ body {
}

&.vs--open .vs__dropdown-toggle {
border-width: var(--border-width-input-focused);
outline: 2px solid var(--color-main-background);
border-color: var(--color-main-text);
border-bottom-color: transparent;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-style: solid;
border-width: var(--border-width-input-focused);
outline: 2px solid var(--color-main-background);
padding: 0;
}

&:not(.vs--disabled, .vs--open) .vs__dropdown-toggle:hover {
outline: 2px solid var(--color-main-background);
border-color: var(--color-main-text);
&:not(.vs--disabled, .vs--open) {
.vs__dropdown-toggle:active,
.vs__dropdown-toggle:focus-within {
outline: 2px solid var(--color-main-background);
border-color: var(--color-main-text);
}
}

&.vs--disabled {
Expand Down Expand Up @@ -1216,6 +1228,10 @@ body {
}
}

.vs__dropdown-toggle {
@include border.inputLikeBorder('.select--legacy', var(--vs-border-color));
}

.vs__dropdown-menu {
border-width: var(--border-width-input-focused) !important;
border-color: var(--color-main-text) !important;
Expand All @@ -1228,7 +1244,7 @@ body {
padding: 4px !important;

&--floating {
/* Fallback styles overidden by programmatically set inline styles */
/* Fallback styles overridden by programmatically set inline styles */
width: max-content;
position: absolute;
top: 0;
Expand Down
47 changes: 8 additions & 39 deletions src/components/NcTextArea/NcTextArea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ export default {

setup() {
const model = useModelMigration('value', 'update:value', true)

return {
isLegacy32,
model,
Expand Down Expand Up @@ -357,6 +358,8 @@ export default {
</script>

<style lang="scss" scoped>
@use '../../assets/input-border.scss' as border;

.textarea {
--input-border-color: var(--color-border-maxcontrast);
--input-border-width-offset: calc(var(--border-width-input-focused, 2px) - var(--border-width-input, 2px));
Expand All @@ -373,42 +376,27 @@ export default {

&__main-wrapper {
height: calc(var(--default-clickable-area) * 2);
padding: var(--border-width-input, 2px);
padding: var(--border-width-input-focused, 2px);
position: relative;

&:not(:has([disabled])):has(textarea:focus),
&:not(:has([disabled])):has(textarea:active) {
padding: 0;
}
}

&__input {
margin: 0;
padding-block: calc(10px + var(--input-border-width-offset));
padding-inline: calc(12px - var(--border-width-input, 2px) + var(--input-border-width-offset)); // align with label 8px margin label + 4px padding label - 2px border input
padding-block: var(--border-radius-element);
padding-inline: 10px; // align with label 8px margin label + 4px padding label - 2px border input
width: 100%;
font-size: var(--default-font-size);
text-overflow: ellipsis;
cursor: pointer;

background-color: var(--color-main-background);
color: var(--color-main-text);
// we use box shadow to create a border as this allows use to have a nice gradient
border: none;
border-radius: var(--border-radius-element, var(--border-radius-large));
box-shadow:
0 -1px var(--input-border-color),
0 0 0 1px color-mix(in srgb, var(--input-border-color), 65% transparent);

&:hover:not([disabled]) {
box-shadow: 0 0 0 1px var(--input-border-color);
}
@include border.inputBorder('.textarea--legacy', var(--input-border-color));

&:active:not([disabled]),
&:focus:not([disabled]) {
--input-border-width-offset: 0px;
--input-border-color: var(--color-main-text);
border: var(--border-width-input-focused, 2px) solid var(--input-border-color);
box-shadow: 0 0 0 2px var(--color-main-background) !important;
}

// Hide placeholder while not focussed -> show label instead (only if internal label is used)
Expand Down Expand Up @@ -492,24 +480,5 @@ export default {
color: var(--color-success-text);
}
}

// for Nextcloud 31 and older we need the old design with only one color
&--legacy {
.textarea__input {
box-shadow: 0 0 0 1px var(--input-border-color);
}

.textarea__main-wrapper:hover:not(:has([disabled])) {
padding: 0;

.textarea__input {
--input-border-color: var(--color-main-text);
// Reset padding offset when focused
--input-border-width-offset: 0px;
border: var(--border-width-input-focused, 2px) solid var(--input-border-color);
box-shadow: 0 0 0 2px var(--color-main-background) !important;
}
}
}
}
</style>
Loading
Loading