VField.sass 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. @use 'sass:map'
  2. @use 'sass:math'
  3. @use 'sass:selector'
  4. @use '../../styles/settings'
  5. @use '../../styles/tools'
  6. @use './variables' as *
  7. @include tools.layer('components')
  8. /* region INPUT */
  9. .v-field
  10. display: grid
  11. grid-template-areas: "prepend-inner field clear append-inner"
  12. grid-template-columns: min-content minmax(0, 1fr) min-content min-content
  13. font-size: $field-font-size
  14. letter-spacing: $field-letter-spacing
  15. max-width: $field-max-width
  16. border-radius: $field-border-radius
  17. contain: layout
  18. flex: 1 0
  19. grid-area: control
  20. position: relative
  21. --v-theme-overlay-multiplier: 1
  22. --v-field-padding-start: #{$field-control-padding-start}
  23. --v-field-padding-end: #{$field-control-padding-end}
  24. --v-field-padding-top: #{$field-control-padding-top}
  25. --v-field-padding-bottom: #{$field-control-padding-bottom}
  26. --v-field-input-padding-top: #{$field-input-padding-top}
  27. --v-field-input-padding-bottom: #{$field-input-padding-bottom}
  28. &--disabled
  29. opacity: var(--v-disabled-opacity)
  30. pointer-events: none
  31. .v-chip
  32. --v-chip-height: #{$field-chip-height}
  33. /* endregion */
  34. /* region MODIFIERS */
  35. .v-field
  36. &--prepended
  37. padding-inline-start: $field-control-affixed-padding
  38. &--appended
  39. padding-inline-end: $field-control-affixed-padding
  40. &--variant-solo,
  41. &--variant-solo-filled
  42. background: $field-control-solo-background
  43. border-color: transparent
  44. color: $field-control-solo-color
  45. @include tools.elevation($field-control-solo-elevation)
  46. &--variant-solo-inverted
  47. background: $field-control-solo-background
  48. border-color: transparent
  49. color: $field-control-solo-inverted-color
  50. @include tools.elevation($field-control-solo-elevation)
  51. &.v-field--focused
  52. color: $field-control-solo-inverted-focused-color
  53. &--variant-filled
  54. border-bottom-left-radius: 0
  55. border-bottom-right-radius: 0
  56. &--variant-solo,
  57. &--variant-solo-inverted,
  58. &--variant-solo-filled,
  59. &--variant-filled
  60. $root: &
  61. @at-root
  62. @include tools.density('v-input', $input-density) using ($modifier)
  63. @at-root #{selector.nest(&, $root)}
  64. --v-input-control-height: #{$field-control-height + $modifier}
  65. --v-field-padding-bottom: #{math.max(0px, $field-control-padding-bottom + $modifier * .5)}
  66. &--variant-outlined,
  67. &--single-line,
  68. &--no-label
  69. --v-field-padding-top: 0px
  70. $root: &
  71. @at-root
  72. @include tools.density('v-input', $input-density) using ($modifier)
  73. @at-root #{selector.nest(&, $root)}
  74. --v-field-padding-bottom: #{16px + $modifier * .5}
  75. &--variant-plain,
  76. &--variant-underlined
  77. $root: &
  78. border-radius: 0
  79. padding: 0
  80. &.v-field
  81. --v-field-padding-start: 0px
  82. --v-field-padding-end: 0px
  83. @at-root
  84. @include tools.density('v-input', $input-density) using ($modifier)
  85. @at-root #{selector.nest(&, $root)}
  86. --v-input-control-height: #{$field-control-underlined-height + $modifier}
  87. --v-field-padding-top: #{math.max(0px, 4px + $modifier * .25)}
  88. --v-field-padding-bottom: #{math.max(0px, $field-control-padding-bottom + $modifier * .5)}
  89. &--flat
  90. box-shadow: none
  91. &--rounded
  92. @include tools.rounded($field-rounded-border-radius)
  93. // These are separate so they can override the default variant styles
  94. &.v-field
  95. &--prepended
  96. --v-field-padding-start: #{$field-control-affixed-inner-padding}
  97. &--appended
  98. --v-field-padding-end: #{$field-control-affixed-inner-padding}
  99. /* endregion */
  100. /* region ELEMENTS */
  101. .v-field__input
  102. align-items: center
  103. color: inherit
  104. column-gap: $field-input-column-gap
  105. display: flex
  106. flex-wrap: wrap
  107. letter-spacing: $field-letter-spacing
  108. opacity: $field-input-opacity
  109. min-height: $field-input-min-height
  110. min-width: 0
  111. padding-inline: var(--v-field-padding-start) var(--v-field-padding-end)
  112. padding-top: var(--v-field-input-padding-top)
  113. padding-bottom: var(--v-field-input-padding-bottom)
  114. position: relative
  115. width: 100%
  116. $root: &
  117. @at-root
  118. @include tools.density('v-input', $input-density) using ($modifier)
  119. @at-root #{selector.nest(&, $root)}
  120. row-gap: #{$field-input-row-gap + $modifier * .25}
  121. input
  122. letter-spacing: inherit
  123. @at-root
  124. & input::placeholder,
  125. input#{&}::placeholder,
  126. textarea#{&}::placeholder
  127. color: currentColor
  128. opacity: var(--v-disabled-opacity)
  129. &:focus,
  130. &:active
  131. outline: none
  132. // Remove Firefox red outline
  133. &:invalid
  134. box-shadow: none
  135. .v-field__field
  136. flex: 1 0
  137. grid-area: field
  138. position: relative
  139. align-items: flex-start
  140. display: flex
  141. /* endregion */
  142. /* region AFFIXES */
  143. .v-field__prepend-inner
  144. grid-area: prepend-inner
  145. padding-inline-end: var(--v-field-padding-after)
  146. .v-field__clearable
  147. grid-area: clear
  148. .v-field__append-inner
  149. grid-area: append-inner
  150. padding-inline-start: var(--v-field-padding-after)
  151. .v-field__append-inner,
  152. .v-field__clearable,
  153. .v-field__prepend-inner
  154. display: flex
  155. align-items: flex-start
  156. padding-top: var(--v-input-padding-top, $field-control-padding-top)
  157. .v-field--center-affix &
  158. align-items: center
  159. padding-top: 0
  160. .v-field.v-field--variant-underlined,
  161. .v-field.v-field--variant-plain
  162. .v-field__append-inner,
  163. .v-field__clearable,
  164. .v-field__prepend-inner
  165. align-items: flex-start
  166. padding-top: $field-input-padding-top
  167. padding-bottom: $field-input-padding-bottom
  168. .v-field__prepend-inner,
  169. .v-field__append-inner
  170. .v-field--focused &
  171. opacity: 1
  172. .v-field__prepend-inner,
  173. .v-field__append-inner,
  174. .v-field__clearable
  175. > .v-icon
  176. opacity: var(--v-medium-emphasis-opacity)
  177. .v-field--disabled &,
  178. .v-field--error &
  179. > .v-icon
  180. opacity: 1
  181. .v-field--error:not(.v-field--disabled) &
  182. > .v-icon
  183. color: rgb(var(--v-theme-error))
  184. .v-field__clearable
  185. cursor: pointer
  186. opacity: 0
  187. overflow: hidden
  188. margin-inline: $field-clearable-margin
  189. transition: $field-transition-timing
  190. transition-property: opacity, transform, width
  191. .v-field--focused &,
  192. .v-field--persistent-clear &
  193. opacity: 1
  194. @media (hover: hover)
  195. .v-field:hover &
  196. opacity: 1
  197. @media (hover: none)
  198. opacity: 1
  199. /* endregion */
  200. /* region LABEL */
  201. .v-label.v-field-label
  202. contain: layout paint
  203. display: block
  204. margin-inline-start: var(--v-field-padding-start)
  205. margin-inline-end: var(--v-field-padding-end)
  206. max-width: calc(100% - var(--v-field-padding-start) - var(--v-field-padding-end))
  207. pointer-events: none
  208. position: absolute
  209. top: var(--v-input-padding-top)
  210. transform-origin: left center
  211. transition: $field-transition-timing
  212. transition-property: opacity, transform
  213. z-index: 1
  214. .v-field--variant-underlined &,
  215. .v-field--variant-plain &
  216. top: calc(var(--v-input-padding-top) + var(--v-field-padding-top))
  217. .v-field--center-affix &
  218. top: 50%
  219. transform: translateY(-50%)
  220. .v-field--active &
  221. visibility: hidden
  222. .v-field--focused &,
  223. .v-field--error &
  224. opacity: 1
  225. .v-field--error:not(.v-field--disabled) &
  226. color: rgb(var(--v-theme-error))
  227. &--floating
  228. --v-field-label-scale: #{$field-label-floating-scale}em
  229. font-size: var(--v-field-label-scale)
  230. visibility: hidden
  231. max-width: 100%
  232. .v-field--center-affix &
  233. transform: none
  234. .v-field.v-field--active &
  235. visibility: unset
  236. .v-field--variant-solo &,
  237. .v-field--variant-solo-inverted &,
  238. .v-field--variant-filled &,
  239. .v-field--variant-solo-filled &
  240. $root: &
  241. @at-root
  242. @include tools.density('v-input', $input-density) using ($modifier)
  243. @at-root #{selector.nest(&, $root)}
  244. top: 7px + $modifier * .25
  245. .v-field--variant-plain &,
  246. .v-field--variant-underlined &
  247. transform: translateY(-16px)
  248. margin: 0
  249. top: var(--v-input-padding-top)
  250. .v-field--variant-outlined &
  251. transform: translateY(-50%)
  252. transform-origin: center
  253. position: static
  254. margin: 0 4px
  255. /* endregion */
  256. /* region OUTLINE */
  257. .v-field__outline
  258. --v-field-border-width: #{$field-border-width}
  259. --v-field-border-opacity: #{$field-outline-opacity}
  260. align-items: stretch
  261. contain: layout
  262. display: flex
  263. height: 100%
  264. left: 0
  265. pointer-events: none
  266. position: absolute
  267. right: 0
  268. width: 100%
  269. @media (hover: hover)
  270. .v-field:hover &
  271. --v-field-border-opacity: var(--v-high-emphasis-opacity)
  272. .v-field--error:not(.v-field--disabled) &
  273. color: rgb(var(--v-theme-error))
  274. .v-field.v-field--focused &,
  275. .v-input.v-input--error &
  276. --v-field-border-opacity: 1
  277. .v-field--variant-outlined.v-field--focused &
  278. --v-field-border-width: #{$field-focused-border-width}
  279. .v-field--variant-filled &,
  280. .v-field--variant-underlined &
  281. &::before
  282. border-color: currentColor
  283. border-style: solid
  284. border-width: 0 0 var(--v-field-border-width)
  285. opacity: var(--v-field-border-opacity)
  286. transition: opacity $field-subtle-transition-timing
  287. @include tools.absolute(true)
  288. .v-field--variant-filled &,
  289. .v-field--variant-underlined &
  290. &::after
  291. border-color: currentColor
  292. border-style: solid
  293. border-width: 0 0 $field-focused-border-width
  294. transform: scaleX(0)
  295. transition: transform $field-transition-timing
  296. @include tools.absolute(true)
  297. @at-root #{selector.append('.v-field--focused', &)}
  298. transform: scaleX(1)
  299. .v-field--variant-outlined &
  300. border-radius: inherit
  301. &__start,
  302. &__notch::before,
  303. &__notch::after,
  304. &__end
  305. border: 0 solid currentColor
  306. opacity: var(--v-field-border-opacity)
  307. transition: opacity $field-subtle-transition-timing
  308. &__start
  309. flex: 0 0 $field-control-affixed-padding
  310. border-top-width: var(--v-field-border-width)
  311. border-bottom-width: var(--v-field-border-width)
  312. border-inline-start-width: var(--v-field-border-width)
  313. border-start-start-radius: inherit
  314. border-start-end-radius: 0
  315. border-end-end-radius: 0
  316. border-end-start-radius: inherit
  317. @at-root
  318. #{selector.append('.v-field--rounded', &)},
  319. #{selector.append('[class^="rounded-"]', &)},
  320. #{selector.append('[class*=" rounded-"]', &)}
  321. flex-basis: calc(var(--v-input-control-height) / 2 + 2px)
  322. @at-root #{selector.append('.v-field--reverse', &)}
  323. border-start-start-radius: 0
  324. border-start-end-radius: inherit
  325. border-end-end-radius: inherit
  326. border-end-start-radius: 0
  327. border-inline-end-width: var(--v-field-border-width)
  328. border-inline-start-width: 0
  329. &__notch
  330. flex: none
  331. position: relative
  332. max-width: calc(100% - $field-control-affixed-padding)
  333. &::before,
  334. &::after
  335. opacity: var(--v-field-border-opacity)
  336. transition: opacity $field-subtle-transition-timing
  337. @include tools.absolute(true)
  338. &::before
  339. border-width: var(--v-field-border-width) 0 0
  340. &::after
  341. bottom: 0
  342. border-width: 0 0 var(--v-field-border-width)
  343. @at-root #{selector.append('.v-field--active', &)}
  344. &::before
  345. opacity: 0
  346. &__end
  347. flex: 1
  348. border-top-width: var(--v-field-border-width)
  349. border-bottom-width: var(--v-field-border-width)
  350. border-inline-end-width: var(--v-field-border-width)
  351. border-start-start-radius: 0
  352. border-start-end-radius: inherit
  353. border-end-end-radius: inherit
  354. border-end-start-radius: 0
  355. @at-root #{selector.append('.v-field--reverse', &)}
  356. border-start-start-radius: inherit
  357. border-start-end-radius: 0
  358. border-end-end-radius: 0
  359. border-end-start-radius: inherit
  360. border-inline-end-width: 0
  361. border-inline-start-width: var(--v-field-border-width)
  362. /* endregion */
  363. /* region LOADER */
  364. .v-field__loader
  365. top: calc(100% - 2px)
  366. left: 0
  367. position: absolute
  368. right: 0
  369. width: 100%
  370. border-top-left-radius: 0
  371. border-top-right-radius: 0
  372. border-bottom-left-radius: inherit
  373. border-bottom-right-radius: inherit
  374. overflow: hidden
  375. .v-field--variant-outlined &
  376. top: calc(100% - 3px)
  377. width: calc(100% - #{$field-border-width} * 2)
  378. left: $field-border-width
  379. /* endregion */
  380. /* region OVERLAY */
  381. .v-field__overlay
  382. border-radius: inherit
  383. pointer-events: none
  384. @include tools.absolute()
  385. .v-field--variant-filled
  386. .v-field__overlay
  387. background-color: currentColor
  388. opacity: $field-overlay-filled-opacity
  389. transition: opacity $field-subtle-transition-timing
  390. &.v-field--has-background .v-field__overlay
  391. opacity: 0
  392. @media (hover: hover)
  393. &:hover .v-field__overlay
  394. opacity: calc((#{$field-overlay-filled-opacity} + #{map.get(settings.$states, 'hover')}) * var(--v-theme-overlay-multiplier))
  395. &.v-field--focused .v-field__overlay
  396. opacity: calc((#{$field-overlay-filled-opacity} + #{map.get(settings.$states, 'focus')}) * var(--v-theme-overlay-multiplier))
  397. .v-field--variant-solo-filled
  398. .v-field__overlay
  399. background-color: currentColor
  400. opacity: $field-overlay-filled-opacity
  401. transition: opacity $field-subtle-transition-timing
  402. @media (hover: hover)
  403. &:hover .v-field__overlay
  404. opacity: calc((#{$field-overlay-filled-opacity} + #{map.get(settings.$states, 'hover')}) * var(--v-theme-overlay-multiplier))
  405. &.v-field--focused .v-field__overlay
  406. opacity: calc((#{$field-overlay-filled-opacity} + #{map.get(settings.$states, 'focus')}) * var(--v-theme-overlay-multiplier))
  407. .v-field--variant-solo-inverted
  408. .v-field__overlay
  409. transition: opacity $field-subtle-transition-timing
  410. &.v-field--has-background .v-field__overlay
  411. opacity: 0
  412. @media (hover: hover)
  413. &:hover .v-field__overlay
  414. opacity: calc((#{.04} + #{map.get(settings.$states, 'hover')}) * var(--v-theme-overlay-multiplier))
  415. &.v-field--focused .v-field__overlay
  416. background-color: $field-overlay-focused-background-color
  417. opacity: 1
  418. /* endregion */
  419. /* region MODIFIERS */
  420. .v-field--reverse
  421. .v-field__field,
  422. .v-field__input,
  423. .v-field__outline
  424. flex-direction: row-reverse
  425. .v-field__input, input
  426. text-align: end
  427. .v-field--variant-filled,
  428. .v-field--variant-underlined
  429. .v-input--disabled &
  430. .v-field__outline::before
  431. border-image: repeating-linear-gradient(to right, $field-disabled-color 0px, $field-disabled-color 2px, transparent 2px, transparent 4px) 1 repeat
  432. .v-field--loading
  433. .v-field__outline::after,
  434. .v-field__outline::before
  435. opacity: 0
  436. /* endregion */