_mdc-text-field-structure.scss 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. @use '@angular/cdk';
  2. @use '../core/style/vendor-prefixes';
  3. @use '../core/tokens/token-utils';
  4. @use '../core/tokens/m2/mdc/filled-text-field' as tokens-mdc-filled-text-field;
  5. @use '../core/tokens/m2/mdc/outlined-text-field' as tokens-mdc-outlined-text-field;
  6. // Includes the structural styles for the form field inherited from MDC.
  7. @mixin private-text-field-structure {
  8. $filled-slots: (
  9. tokens-mdc-filled-text-field.$prefix,
  10. tokens-mdc-filled-text-field.get-token-slots()
  11. );
  12. $outlined-slots: (
  13. tokens-mdc-outlined-text-field.$prefix,
  14. tokens-mdc-outlined-text-field.get-token-slots()
  15. );
  16. .mdc-text-field {
  17. display: inline-flex;
  18. align-items: baseline;
  19. padding: 0 16px;
  20. position: relative;
  21. box-sizing: border-box;
  22. overflow: hidden;
  23. will-change: opacity, transform, color;
  24. // TODO(crisbeto): The filled form field overrides these while the outlined doesn't.
  25. // The correct thing to do would be to remove them from here and have the one based on the
  26. // token in the outlined appearance. We keep them as is for now to avoid screenshot diffs.
  27. border-top-left-radius: 4px;
  28. border-top-right-radius: 4px;
  29. border-bottom-right-radius: 0;
  30. border-bottom-left-radius: 0;
  31. }
  32. .mdc-text-field__input {
  33. width: 100%;
  34. min-width: 0;
  35. border: none;
  36. border-radius: 0;
  37. background: none;
  38. padding: 0;
  39. -moz-appearance: none;
  40. -webkit-appearance: none;
  41. // TODO(crisbeto): this height gets overwritten eventually, but there are some internal
  42. // tests that depend on this being here in weird ways so we're keeping it around for now.
  43. height: 28px;
  44. // Note that while this style and the `-ms-clear` are identical, we can't combine
  45. // them because if one of them isn't supported, it'll invalidate the whole rule.
  46. &::-webkit-calendar-picker-indicator {
  47. display: none;
  48. }
  49. &::-ms-clear {
  50. display: none;
  51. }
  52. &:focus {
  53. outline: none;
  54. }
  55. &:invalid {
  56. box-shadow: none;
  57. }
  58. @include vendor-prefixes.input-placeholder {
  59. opacity: 0;
  60. }
  61. .mdc-text-field--no-label &,
  62. .mdc-text-field--focused & {
  63. @include vendor-prefixes.input-placeholder {
  64. opacity: 1;
  65. }
  66. }
  67. .mdc-text-field--disabled:not(.mdc-text-field--no-label) &.mat-mdc-input-disabled-interactive {
  68. @include vendor-prefixes.input-placeholder {
  69. opacity: 0;
  70. }
  71. }
  72. .mdc-text-field--outlined &,
  73. .mdc-text-field--filled.mdc-text-field--no-label & {
  74. height: 100%;
  75. }
  76. .mdc-text-field--outlined & {
  77. display: flex;
  78. border: none !important;
  79. background-color: transparent;
  80. }
  81. .mdc-text-field--disabled & {
  82. pointer-events: auto;
  83. }
  84. @include token-utils.use-tokens($filled-slots...) {
  85. @include _input-tokens('.mdc-text-field--filled');
  86. }
  87. @include token-utils.use-tokens($outlined-slots...) {
  88. @include _input-tokens('.mdc-text-field--outlined');
  89. }
  90. @include cdk.high-contrast {
  91. .mdc-text-field--disabled & {
  92. background-color: Window;
  93. }
  94. }
  95. }
  96. .mdc-text-field--filled {
  97. height: 56px;
  98. border-bottom-right-radius: 0;
  99. border-bottom-left-radius: 0;
  100. @include token-utils.use-tokens($filled-slots...) {
  101. @include token-utils.create-token-slot(border-top-left-radius, container-shape);
  102. @include token-utils.create-token-slot(border-top-right-radius, container-shape);
  103. &:not(.mdc-text-field--disabled) {
  104. @include token-utils.create-token-slot(background-color, container-color);
  105. }
  106. &.mdc-text-field--disabled {
  107. @include token-utils.create-token-slot(background-color, disabled-container-color);
  108. }
  109. }
  110. }
  111. .mdc-text-field--outlined {
  112. height: 56px;
  113. overflow: visible;
  114. @include token-utils.use-tokens($outlined-slots...) {
  115. $shape-var: token-utils.get-token-variable(container-shape);
  116. padding-right: max(16px, #{$shape-var});
  117. padding-left: max(16px, calc(#{$shape-var} + 4px));
  118. [dir='rtl'] & {
  119. padding-right: max(16px, calc(#{$shape-var} + 4px));
  120. padding-left: max(16px, #{$shape-var});
  121. }
  122. }
  123. }
  124. .mdc-floating-label {
  125. position: absolute;
  126. left: 0;
  127. transform-origin: left top;
  128. line-height: 1.15rem;
  129. text-align: left;
  130. text-overflow: ellipsis;
  131. white-space: nowrap;
  132. cursor: text;
  133. overflow: hidden;
  134. will-change: transform;
  135. [dir='rtl'] & {
  136. right: 0;
  137. left: auto;
  138. transform-origin: right top;
  139. text-align: right;
  140. }
  141. .mdc-text-field & {
  142. top: 50%;
  143. transform: translateY(-50%);
  144. pointer-events: none;
  145. }
  146. .mdc-notched-outline & {
  147. display: inline-block;
  148. position: relative;
  149. max-width: 100%;
  150. }
  151. .mdc-text-field--outlined & {
  152. left: 4px;
  153. right: auto;
  154. }
  155. [dir='rtl'] .mdc-text-field--outlined & {
  156. left: auto;
  157. right: 4px;
  158. }
  159. .mdc-text-field--filled & {
  160. left: 16px;
  161. right: auto;
  162. }
  163. [dir='rtl'] .mdc-text-field--filled & {
  164. left: auto;
  165. right: 16px;
  166. }
  167. .mdc-text-field--disabled & {
  168. cursor: default;
  169. @include cdk.high-contrast {
  170. z-index: 1;
  171. }
  172. }
  173. .mdc-text-field--filled.mdc-text-field--no-label & {
  174. display: none;
  175. }
  176. @include token-utils.use-tokens($filled-slots...) {
  177. @include _floating-label-tokens('.mdc-text-field--filled');
  178. }
  179. @include token-utils.use-tokens($outlined-slots...) {
  180. @include _floating-label-tokens('.mdc-text-field--outlined');
  181. }
  182. }
  183. .mdc-floating-label--float-above {
  184. cursor: auto;
  185. transform: translateY(-106%) scale(0.75);
  186. .mdc-text-field--filled & {
  187. transform: translateY(-106%) scale(0.75);
  188. }
  189. .mdc-text-field--outlined & {
  190. transform: translateY(-37.25px) scale(1);
  191. font-size: 0.75rem;
  192. }
  193. .mdc-notched-outline & {
  194. text-overflow: clip;
  195. }
  196. .mdc-notched-outline--upgraded & {
  197. max-width: 133.3333333333%;
  198. }
  199. .mdc-text-field--outlined.mdc-notched-outline--upgraded &,
  200. .mdc-text-field--outlined .mdc-notched-outline--upgraded & {
  201. transform: translateY(-34.75px) scale(0.75);
  202. }
  203. .mdc-text-field--outlined.mdc-notched-outline--upgraded &,
  204. .mdc-text-field--outlined .mdc-notched-outline--upgraded & {
  205. font-size: 1rem;
  206. }
  207. }
  208. .mdc-floating-label--required {
  209. &:not(.mdc-floating-label--hide-required-marker)::after {
  210. margin-left: 1px;
  211. margin-right: 0;
  212. content: '*';
  213. [dir='rtl'] & {
  214. margin-left: 0;
  215. margin-right: 1px;
  216. }
  217. }
  218. }
  219. .mdc-notched-outline {
  220. display: flex;
  221. position: absolute;
  222. top: 0;
  223. right: 0;
  224. left: 0;
  225. box-sizing: border-box;
  226. width: 100%;
  227. max-width: 100%;
  228. height: 100%;
  229. text-align: left;
  230. pointer-events: none;
  231. [dir='rtl'] & {
  232. text-align: right;
  233. }
  234. .mdc-text-field--outlined & {
  235. z-index: 1;
  236. }
  237. }
  238. .mat-mdc-notch-piece {
  239. box-sizing: border-box;
  240. height: 100%;
  241. pointer-events: none;
  242. border-top: 1px solid;
  243. border-bottom: 1px solid;
  244. .mdc-text-field--focused & {
  245. border-width: 2px;
  246. }
  247. @include token-utils.use-tokens($outlined-slots...) {
  248. // Moved out into variables because the selectors we inherited were too long.
  249. $enabled-selector: '.mdc-text-field--outlined:not(.mdc-text-field--disabled)';
  250. $hover-selector: ':not(.mdc-text-field--focused):hover';
  251. #{$enabled-selector} & {
  252. @include token-utils.create-token-slot(border-color, outline-color);
  253. @include token-utils.create-token-slot(border-width, outline-width);
  254. }
  255. #{$enabled-selector}#{$hover-selector} & {
  256. @include token-utils.create-token-slot(border-color, hover-outline-color);
  257. }
  258. #{$enabled-selector}.mdc-text-field--focused & {
  259. @include token-utils.create-token-slot(border-color, focus-outline-color);
  260. }
  261. .mdc-text-field--outlined.mdc-text-field--disabled & {
  262. @include token-utils.create-token-slot(border-color, disabled-outline-color);
  263. }
  264. #{$enabled-selector}.mdc-text-field--invalid & {
  265. @include token-utils.create-token-slot(border-color, error-outline-color);
  266. }
  267. #{$enabled-selector}.mdc-text-field--invalid#{$hover-selector} .mdc-notched-outline & {
  268. @include token-utils.create-token-slot(border-color, error-hover-outline-color);
  269. }
  270. #{$enabled-selector}.mdc-text-field--invalid.mdc-text-field--focused & {
  271. @include token-utils.create-token-slot(border-color, error-focus-outline-color);
  272. }
  273. #{$enabled-selector}.mdc-text-field--focused .mdc-notched-outline & {
  274. @include token-utils.create-token-slot(border-width, focus-outline-width);
  275. }
  276. }
  277. }
  278. .mdc-notched-outline__leading {
  279. border-left: 1px solid;
  280. border-right: none;
  281. border-top-right-radius: 0;
  282. border-bottom-right-radius: 0;
  283. @include token-utils.use-tokens($outlined-slots...) {
  284. @include token-utils.create-token-slot(border-top-left-radius, container-shape);
  285. @include token-utils.create-token-slot(border-bottom-left-radius, container-shape);
  286. .mdc-text-field--outlined .mdc-notched-outline & {
  287. $shape-var: token-utils.get-token-variable(container-shape);
  288. width: max(12px, #{$shape-var});
  289. }
  290. }
  291. [dir='rtl'] & {
  292. border-left: none;
  293. border-right: 1px solid;
  294. border-bottom-left-radius: 0;
  295. border-top-left-radius: 0;
  296. @include token-utils.use-tokens($outlined-slots...) {
  297. @include token-utils.create-token-slot(border-top-right-radius, container-shape);
  298. @include token-utils.create-token-slot(border-bottom-right-radius, container-shape);
  299. }
  300. }
  301. }
  302. .mdc-notched-outline__trailing {
  303. flex-grow: 1;
  304. border-left: none;
  305. border-right: 1px solid;
  306. border-top-left-radius: 0;
  307. border-bottom-left-radius: 0;
  308. @include token-utils.use-tokens($outlined-slots...) {
  309. @include token-utils.create-token-slot(border-top-right-radius, container-shape);
  310. @include token-utils.create-token-slot(border-bottom-right-radius, container-shape);
  311. }
  312. [dir='rtl'] & {
  313. border-left: 1px solid;
  314. border-right: none;
  315. border-top-right-radius: 0;
  316. border-bottom-right-radius: 0;
  317. @include token-utils.use-tokens($outlined-slots...) {
  318. @include token-utils.create-token-slot(border-top-left-radius, container-shape);
  319. @include token-utils.create-token-slot(border-bottom-left-radius, container-shape);
  320. }
  321. }
  322. }
  323. .mdc-notched-outline__notch {
  324. flex: 0 0 auto;
  325. width: auto;
  326. @include token-utils.use-tokens($outlined-slots...) {
  327. .mdc-text-field--outlined .mdc-notched-outline & {
  328. $shape-var: token-utils.get-token-variable(container-shape);
  329. max-width: min(
  330. var(--mat-form-field-notch-max-width, 100%),
  331. calc(100% - max(12px, #{$shape-var}) * 2)
  332. );
  333. }
  334. }
  335. .mdc-text-field--outlined .mdc-notched-outline--notched & {
  336. padding-top: 1px;
  337. }
  338. .mdc-text-field--focused.mdc-text-field--outlined .mdc-notched-outline--notched & {
  339. padding-top: 2px;
  340. }
  341. .mdc-notched-outline--notched & {
  342. padding-left: 0;
  343. padding-right: 8px;
  344. border-top: none;
  345. --mat-form-field-notch-max-width: 100%;
  346. }
  347. [dir='rtl'] .mdc-notched-outline--notched & {
  348. padding-left: 8px;
  349. padding-right: 0;
  350. }
  351. .mdc-notched-outline--no-label & {
  352. display: none;
  353. }
  354. }
  355. .mdc-line-ripple {
  356. &::before,
  357. &::after {
  358. position: absolute;
  359. bottom: 0;
  360. left: 0;
  361. width: 100%;
  362. border-bottom-style: solid;
  363. content: '';
  364. }
  365. &::before {
  366. z-index: 1;
  367. @include token-utils.use-tokens($filled-slots...) {
  368. $enabled-field: '.mdc-text-field--filled:not(.mdc-text-field--disabled)';
  369. @include token-utils.create-token-slot(border-bottom-width, active-indicator-height);
  370. #{$enabled-field} & {
  371. @include token-utils.create-token-slot(border-bottom-color, active-indicator-color);
  372. }
  373. #{$enabled-field}:not(.mdc-text-field--focused):hover & {
  374. @include token-utils.create-token-slot(border-bottom-color, hover-active-indicator-color);
  375. }
  376. .mdc-text-field--filled.mdc-text-field--disabled & {
  377. @include token-utils.create-token-slot(
  378. border-bottom-color,
  379. disabled-active-indicator-color
  380. );
  381. }
  382. #{$enabled-field}.mdc-text-field--invalid & {
  383. @include token-utils.create-token-slot(border-bottom-color, error-active-indicator-color);
  384. }
  385. #{$enabled-field}.mdc-text-field--invalid:not(.mdc-text-field--focused):hover & {
  386. @include token-utils.create-token-slot(
  387. border-bottom-color,
  388. error-hover-active-indicator-color
  389. );
  390. }
  391. }
  392. }
  393. &::after {
  394. transform: scaleX(0);
  395. opacity: 0;
  396. z-index: 2;
  397. @include token-utils.use-tokens($filled-slots...) {
  398. .mdc-text-field--filled & {
  399. @include token-utils.create-token-slot(
  400. border-bottom-width,
  401. focus-active-indicator-height
  402. );
  403. }
  404. .mdc-text-field--filled:not(.mdc-text-field--disabled) & {
  405. @include token-utils.create-token-slot(border-bottom-color, focus-active-indicator-color);
  406. }
  407. .mdc-text-field--filled.mdc-text-field--invalid:not(.mdc-text-field--disabled) & {
  408. @include token-utils.create-token-slot(
  409. border-bottom-color,
  410. error-focus-active-indicator-color
  411. );
  412. }
  413. }
  414. }
  415. }
  416. .mdc-line-ripple--active::after {
  417. transform: scaleX(1);
  418. opacity: 1;
  419. }
  420. .mdc-line-ripple--deactivating::after {
  421. opacity: 0;
  422. }
  423. .mdc-text-field--disabled {
  424. pointer-events: none;
  425. }
  426. }
  427. // Includes the tokens for the floating label for a specific form field variant.
  428. @mixin _floating-label-tokens($selector) {
  429. $enabled-field: '#{$selector}:not(.mdc-text-field--disabled)';
  430. #{$enabled-field} & {
  431. @include token-utils.create-token-slot(color, label-text-color);
  432. }
  433. #{$enabled-field}.mdc-text-field--focused & {
  434. @include token-utils.create-token-slot(color, focus-label-text-color);
  435. }
  436. #{$enabled-field}:not(.mdc-text-field--focused):hover & {
  437. @include token-utils.create-token-slot(color, hover-label-text-color);
  438. }
  439. #{$selector}.mdc-text-field--disabled & {
  440. @include token-utils.create-token-slot(color, disabled-label-text-color);
  441. }
  442. #{$enabled-field}.mdc-text-field--invalid & {
  443. @include token-utils.create-token-slot(color, error-label-text-color);
  444. }
  445. #{$enabled-field}.mdc-text-field--invalid.mdc-text-field--focused & {
  446. @include token-utils.create-token-slot(color, error-focus-label-text-color);
  447. }
  448. #{$enabled-field}.mdc-text-field--invalid:not(.mdc-text-field--disabled):hover & {
  449. @include token-utils.create-token-slot(color, error-hover-label-text-color);
  450. }
  451. #{$selector} & {
  452. @include token-utils.create-token-slot(font-family, label-text-font);
  453. @include token-utils.create-token-slot(font-size, label-text-size);
  454. @include token-utils.create-token-slot(font-weight, label-text-weight);
  455. @include token-utils.create-token-slot(letter-spacing, label-text-tracking);
  456. }
  457. }
  458. // Includes the tokens for the input for a specific form field variant.
  459. @mixin _input-tokens($selector) {
  460. #{$selector}:not(.mdc-text-field--disabled) & {
  461. @include token-utils.create-token-slot(color, input-text-color);
  462. @include token-utils.create-token-slot(caret-color, caret-color);
  463. @include vendor-prefixes.input-placeholder {
  464. @include token-utils.create-token-slot(color, input-text-placeholder-color);
  465. }
  466. }
  467. #{$selector}.mdc-text-field--invalid:not(.mdc-text-field--disabled) & {
  468. @include token-utils.create-token-slot(caret-color, error-caret-color);
  469. }
  470. #{$selector}.mdc-text-field--disabled & {
  471. @include token-utils.create-token-slot(color, disabled-input-text-color);
  472. }
  473. }
  474. // Includes the animation styles for the form field inherited from MDC.
  475. @mixin private-text-field-animations {
  476. $timing-curve: cubic-bezier(0.4, 0, 0.2, 1);
  477. .mdc-floating-label {
  478. transition:
  479. transform 150ms $timing-curve,
  480. color 150ms $timing-curve;
  481. }
  482. .mdc-text-field__input {
  483. transition: opacity 150ms $timing-curve;
  484. @include vendor-prefixes.input-placeholder {
  485. transition: opacity 67ms $timing-curve;
  486. }
  487. }
  488. &.mdc-text-field--no-label,
  489. &.mdc-text-field--focused {
  490. .mdc-text-field__input {
  491. @include vendor-prefixes.input-placeholder {
  492. transition-delay: 40ms;
  493. transition-duration: 110ms;
  494. }
  495. }
  496. }
  497. .mdc-text-field--filled:not(.mdc-ripple-upgraded):focus .mdc-text-field__ripple::before {
  498. transition-duration: 75ms;
  499. }
  500. .mdc-line-ripple::after {
  501. transition: transform 180ms $timing-curve, opacity 180ms $timing-curve;
  502. }
  503. .mat-mdc-form-field-hint-wrapper,
  504. .mat-mdc-form-field-error-wrapper {
  505. animation-duration: 300ms;
  506. }
  507. }