opacity.test.js 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. import { run, html, css } from './util/run'
  2. test('opacity', () => {
  3. let config = {
  4. darkMode: 'class',
  5. content: [
  6. {
  7. raw: html`
  8. <div class="divide-black"></div>
  9. <div class="border-black"></div>
  10. <div class="bg-black"></div>
  11. <div class="text-black"></div>
  12. <div class="placeholder-black"></div>
  13. `,
  14. },
  15. ],
  16. corePlugins: {
  17. backgroundOpacity: false,
  18. borderOpacity: false,
  19. divideOpacity: false,
  20. placeholderOpacity: false,
  21. textOpacity: false,
  22. },
  23. }
  24. return run('@tailwind utilities', config).then((result) => {
  25. expect(result.css).toMatchFormattedCss(css`
  26. .divide-black > :not([hidden]) ~ :not([hidden]),
  27. .border-black {
  28. border-color: #000;
  29. }
  30. .bg-black {
  31. background-color: #000;
  32. }
  33. .text-black,
  34. .placeholder-black::placeholder {
  35. color: #000;
  36. }
  37. `)
  38. })
  39. })
  40. test('colors defined as functions work when opacity plugins are disabled', () => {
  41. let config = {
  42. darkMode: 'class',
  43. content: [
  44. {
  45. raw: html`
  46. <div class="divide-primary"></div>
  47. <div class="border-primary"></div>
  48. <div class="bg-primary"></div>
  49. <div class="text-primary"></div>
  50. <div class="placeholder-primary"></div>
  51. `,
  52. },
  53. ],
  54. theme: {
  55. colors: {
  56. primary: ({ opacityValue }) =>
  57. opacityValue === undefined
  58. ? 'rgb(var(--color-primary))'
  59. : `rgb(var(--color-primary) / ${opacityValue})`,
  60. },
  61. },
  62. corePlugins: {
  63. backgroundOpacity: false,
  64. borderOpacity: false,
  65. divideOpacity: false,
  66. placeholderOpacity: false,
  67. textOpacity: false,
  68. },
  69. }
  70. return run('@tailwind utilities', config).then((result) => {
  71. expect(result.css).toMatchFormattedCss(css`
  72. .divide-primary > :not([hidden]) ~ :not([hidden]),
  73. .border-primary {
  74. border-color: rgb(var(--color-primary));
  75. }
  76. .bg-primary {
  77. background-color: rgb(var(--color-primary));
  78. }
  79. .text-primary,
  80. .placeholder-primary::placeholder {
  81. color: rgb(var(--color-primary));
  82. }
  83. `)
  84. })
  85. })
  86. it('can use <alpha-value> defining custom properties for colors (opacity plugins enabled)', () => {
  87. let config = {
  88. content: [
  89. {
  90. raw: html`
  91. <div class="divide-primary"></div>
  92. <div class="divide-primary divide-opacity-50"></div>
  93. <div class="border-primary"></div>
  94. <div class="border-primary border-opacity-50"></div>
  95. <div class="bg-primary"></div>
  96. <div class="bg-primary bg-opacity-50"></div>
  97. <div class="text-primary"></div>
  98. <div class="text-primary text-opacity-50"></div>
  99. <div class="placeholder-primary"></div>
  100. <div class="placeholder-primary placeholder-opacity-50"></div>
  101. <div class="ring-primary"></div>
  102. <div class="ring-primary ring-opacity-50"></div>
  103. `,
  104. },
  105. ],
  106. theme: {
  107. colors: {
  108. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  109. },
  110. },
  111. }
  112. return run('@tailwind utilities', config).then((result) => {
  113. expect(result.css).toMatchFormattedCss(css`
  114. .divide-primary > :not([hidden]) ~ :not([hidden]) {
  115. --tw-divide-opacity: 1;
  116. border-color: rgb(var(--color-primary) / var(--tw-divide-opacity));
  117. }
  118. .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) {
  119. --tw-divide-opacity: 0.5;
  120. }
  121. .border-primary {
  122. --tw-border-opacity: 1;
  123. border-color: rgb(var(--color-primary) / var(--tw-border-opacity));
  124. }
  125. .border-opacity-50 {
  126. --tw-border-opacity: 0.5;
  127. }
  128. .bg-primary {
  129. --tw-bg-opacity: 1;
  130. background-color: rgb(var(--color-primary) / var(--tw-bg-opacity));
  131. }
  132. .bg-opacity-50 {
  133. --tw-bg-opacity: 0.5;
  134. }
  135. .text-primary {
  136. --tw-text-opacity: 1;
  137. color: rgb(var(--color-primary) / var(--tw-text-opacity));
  138. }
  139. .text-opacity-50 {
  140. --tw-text-opacity: 0.5;
  141. }
  142. .placeholder-primary::placeholder {
  143. --tw-placeholder-opacity: 1;
  144. color: rgb(var(--color-primary) / var(--tw-placeholder-opacity));
  145. }
  146. .placeholder-opacity-50::placeholder {
  147. --tw-placeholder-opacity: 0.5;
  148. }
  149. .ring-primary {
  150. --tw-ring-opacity: 1;
  151. --tw-ring-color: rgb(var(--color-primary) / var(--tw-ring-opacity));
  152. }
  153. .ring-opacity-50 {
  154. --tw-ring-opacity: 0.5;
  155. }
  156. `)
  157. })
  158. })
  159. it('can use rgb helper when defining custom properties for colors (opacity plugins disabled)', () => {
  160. let config = {
  161. content: [
  162. {
  163. raw: html`
  164. <div class="divide-primary"></div>
  165. <div class="divide-primary/50"></div>
  166. <div class="border-primary"></div>
  167. <div class="border-primary/50"></div>
  168. <div class="bg-primary"></div>
  169. <div class="bg-primary/50"></div>
  170. <div class="text-primary"></div>
  171. <div class="text-primary/50"></div>
  172. <div class="placeholder-primary"></div>
  173. <div class="placeholder-primary/50"></div>
  174. <div class="ring-primary"></div>
  175. <div class="ring-primary/50"></div>
  176. `,
  177. },
  178. ],
  179. theme: {
  180. colors: {
  181. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  182. },
  183. },
  184. corePlugins: {
  185. backgroundOpacity: false,
  186. borderOpacity: false,
  187. divideOpacity: false,
  188. placeholderOpacity: false,
  189. textOpacity: false,
  190. ringOpacity: false,
  191. },
  192. }
  193. return run('@tailwind utilities', config).then((result) => {
  194. expect(result.css).toMatchFormattedCss(css`
  195. .divide-primary > :not([hidden]) ~ :not([hidden]) {
  196. border-color: rgb(var(--color-primary) / 1);
  197. }
  198. .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) {
  199. border-color: rgb(var(--color-primary) / 0.5);
  200. }
  201. .border-primary {
  202. border-color: rgb(var(--color-primary) / 1);
  203. }
  204. .border-primary\/50 {
  205. border-color: rgb(var(--color-primary) / 0.5);
  206. }
  207. .bg-primary {
  208. background-color: rgb(var(--color-primary) / 1);
  209. }
  210. .bg-primary\/50 {
  211. background-color: rgb(var(--color-primary) / 0.5);
  212. }
  213. .text-primary {
  214. color: rgb(var(--color-primary) / 1);
  215. }
  216. .text-primary\/50 {
  217. color: rgb(var(--color-primary) / 0.5);
  218. }
  219. .placeholder-primary::placeholder {
  220. color: rgb(var(--color-primary) / 1);
  221. }
  222. .placeholder-primary\/50::placeholder {
  223. color: rgb(var(--color-primary) / 0.5);
  224. }
  225. .ring-primary {
  226. --tw-ring-color: rgb(var(--color-primary) / 1);
  227. }
  228. .ring-primary\/50 {
  229. --tw-ring-color: rgb(var(--color-primary) / 0.5);
  230. }
  231. `)
  232. })
  233. })
  234. it('can use hsl helper when defining custom properties for colors (opacity plugins enabled)', () => {
  235. let config = {
  236. content: [
  237. {
  238. raw: html`
  239. <div class="divide-primary"></div>
  240. <div class="divide-primary divide-opacity-50"></div>
  241. <div class="border-primary"></div>
  242. <div class="border-primary border-opacity-50"></div>
  243. <div class="bg-primary"></div>
  244. <div class="bg-primary bg-opacity-50"></div>
  245. <div class="text-primary"></div>
  246. <div class="text-primary text-opacity-50"></div>
  247. <div class="placeholder-primary"></div>
  248. <div class="placeholder-primary placeholder-opacity-50"></div>
  249. <div class="ring-primary"></div>
  250. <div class="ring-primary ring-opacity-50"></div>
  251. `,
  252. },
  253. ],
  254. theme: {
  255. colors: {
  256. primary: 'hsl(var(--color-primary) / <alpha-value>)',
  257. },
  258. },
  259. }
  260. return run('@tailwind utilities', config).then((result) => {
  261. expect(result.css).toMatchFormattedCss(css`
  262. .divide-primary > :not([hidden]) ~ :not([hidden]) {
  263. --tw-divide-opacity: 1;
  264. border-color: hsl(var(--color-primary) / var(--tw-divide-opacity));
  265. }
  266. .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) {
  267. --tw-divide-opacity: 0.5;
  268. }
  269. .border-primary {
  270. --tw-border-opacity: 1;
  271. border-color: hsl(var(--color-primary) / var(--tw-border-opacity));
  272. }
  273. .border-opacity-50 {
  274. --tw-border-opacity: 0.5;
  275. }
  276. .bg-primary {
  277. --tw-bg-opacity: 1;
  278. background-color: hsl(var(--color-primary) / var(--tw-bg-opacity));
  279. }
  280. .bg-opacity-50 {
  281. --tw-bg-opacity: 0.5;
  282. }
  283. .text-primary {
  284. --tw-text-opacity: 1;
  285. color: hsl(var(--color-primary) / var(--tw-text-opacity));
  286. }
  287. .text-opacity-50 {
  288. --tw-text-opacity: 0.5;
  289. }
  290. .placeholder-primary::placeholder {
  291. --tw-placeholder-opacity: 1;
  292. color: hsl(var(--color-primary) / var(--tw-placeholder-opacity));
  293. }
  294. .placeholder-opacity-50::placeholder {
  295. --tw-placeholder-opacity: 0.5;
  296. }
  297. .ring-primary {
  298. --tw-ring-opacity: 1;
  299. --tw-ring-color: hsl(var(--color-primary) / var(--tw-ring-opacity));
  300. }
  301. .ring-opacity-50 {
  302. --tw-ring-opacity: 0.5;
  303. }
  304. `)
  305. })
  306. })
  307. it('can use hsl helper when defining custom properties for colors (opacity plugins disabled)', () => {
  308. let config = {
  309. content: [
  310. {
  311. raw: html`
  312. <div class="divide-primary"></div>
  313. <div class="divide-primary/50"></div>
  314. <div class="border-primary"></div>
  315. <div class="border-primary/50"></div>
  316. <div class="bg-primary"></div>
  317. <div class="bg-primary/50"></div>
  318. <div class="text-primary"></div>
  319. <div class="text-primary/50"></div>
  320. <div class="placeholder-primary"></div>
  321. <div class="placeholder-primary/50"></div>
  322. <div class="ring-primary"></div>
  323. <div class="ring-primary/50"></div>
  324. `,
  325. },
  326. ],
  327. theme: {
  328. colors: {
  329. primary: 'hsl(var(--color-primary) / <alpha-value>)',
  330. },
  331. },
  332. corePlugins: {
  333. backgroundOpacity: false,
  334. borderOpacity: false,
  335. divideOpacity: false,
  336. placeholderOpacity: false,
  337. textOpacity: false,
  338. ringOpacity: false,
  339. },
  340. }
  341. return run('@tailwind utilities', config).then((result) => {
  342. expect(result.css).toMatchFormattedCss(css`
  343. .divide-primary > :not([hidden]) ~ :not([hidden]) {
  344. border-color: hsl(var(--color-primary) / 1);
  345. }
  346. .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) {
  347. border-color: hsl(var(--color-primary) / 0.5);
  348. }
  349. .border-primary {
  350. border-color: hsl(var(--color-primary) / 1);
  351. }
  352. .border-primary\/50 {
  353. border-color: hsl(var(--color-primary) / 0.5);
  354. }
  355. .bg-primary {
  356. background-color: hsl(var(--color-primary) / 1);
  357. }
  358. .bg-primary\/50 {
  359. background-color: hsl(var(--color-primary) / 0.5);
  360. }
  361. .text-primary {
  362. color: hsl(var(--color-primary) / 1);
  363. }
  364. .text-primary\/50 {
  365. color: hsl(var(--color-primary) / 0.5);
  366. }
  367. .placeholder-primary::placeholder {
  368. color: hsl(var(--color-primary) / 1);
  369. }
  370. .placeholder-primary\/50::placeholder {
  371. color: hsl(var(--color-primary) / 0.5);
  372. }
  373. .ring-primary {
  374. --tw-ring-color: hsl(var(--color-primary) / 1);
  375. }
  376. .ring-primary\/50 {
  377. --tw-ring-color: hsl(var(--color-primary) / 0.5);
  378. }
  379. `)
  380. })
  381. })
  382. test('Theme function in JS can apply alpha values to colors (1)', () => {
  383. let input = css`
  384. @tailwind utilities;
  385. `
  386. let output = css`
  387. .text-foo {
  388. color: #3b82f680;
  389. }
  390. `
  391. return run(input, {
  392. content: [{ raw: html`text-foo` }],
  393. corePlugins: { textOpacity: false },
  394. theme: {
  395. colors: { blue: { 500: '#3b82f6' } },
  396. extend: {
  397. textColor: ({ theme }) => ({
  398. foo: theme('colors.blue.500 / 50%'),
  399. }),
  400. },
  401. },
  402. }).then((result) => {
  403. expect(result.css).toMatchFormattedCss(output)
  404. expect(result.warnings().length).toBe(0)
  405. })
  406. })
  407. test('Theme function in JS can apply alpha values to colors (2)', () => {
  408. let input = css`
  409. @tailwind utilities;
  410. `
  411. let output = css`
  412. .text-foo {
  413. color: #3b82f680;
  414. }
  415. `
  416. return run(input, {
  417. content: [{ raw: html`text-foo` }],
  418. corePlugins: { textOpacity: false },
  419. theme: {
  420. colors: { blue: { 500: '#3b82f6' } },
  421. extend: {
  422. textColor: ({ theme }) => ({
  423. foo: theme('colors.blue.500 / 0.5'),
  424. }),
  425. },
  426. },
  427. }).then((result) => {
  428. expect(result.css).toMatchFormattedCss(output)
  429. expect(result.warnings().length).toBe(0)
  430. })
  431. })
  432. test('Theme function in JS can apply alpha values to colors (3)', () => {
  433. let input = css`
  434. @tailwind utilities;
  435. `
  436. let output = css`
  437. .text-foo {
  438. color: rgb(59 130 246 / var(--my-alpha));
  439. }
  440. `
  441. return run(input, {
  442. content: [{ raw: html`text-foo` }],
  443. corePlugins: { textOpacity: false },
  444. theme: {
  445. colors: { blue: { 500: '#3b82f6' } },
  446. extend: {
  447. textColor: ({ theme }) => ({
  448. foo: theme('colors.blue.500 / var(--my-alpha)'),
  449. }),
  450. },
  451. },
  452. }).then((result) => {
  453. expect(result.css).toMatchFormattedCss(output)
  454. expect(result.warnings().length).toBe(0)
  455. })
  456. })
  457. test('Theme function in JS can apply alpha values to colors (4)', () => {
  458. let input = css`
  459. @tailwind utilities;
  460. `
  461. let output = css`
  462. .text-foo {
  463. color: #3c83f680;
  464. }
  465. `
  466. return run(input, {
  467. content: [{ raw: html`text-foo` }],
  468. corePlugins: { textOpacity: false },
  469. theme: {
  470. colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
  471. extend: {
  472. textColor: ({ theme }) => ({
  473. foo: theme('colors.blue.500 / 50%'),
  474. }),
  475. },
  476. },
  477. }).then((result) => {
  478. expect(result.css).toMatchFormattedCss(output)
  479. expect(result.warnings().length).toBe(0)
  480. })
  481. })
  482. test('Theme function in JS can apply alpha values to colors (5)', () => {
  483. let input = css`
  484. @tailwind utilities;
  485. `
  486. let output = css`
  487. .text-foo {
  488. color: #3c83f680;
  489. }
  490. `
  491. return run(input, {
  492. content: [{ raw: html`text-foo` }],
  493. corePlugins: { textOpacity: false },
  494. theme: {
  495. colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
  496. extend: {
  497. textColor: ({ theme }) => ({
  498. foo: theme('colors.blue.500 / 0.5'),
  499. }),
  500. },
  501. },
  502. }).then((result) => {
  503. expect(result.css).toMatchFormattedCss(output)
  504. expect(result.warnings().length).toBe(0)
  505. })
  506. })
  507. test('Theme function in JS can apply alpha values to colors (6)', () => {
  508. let input = css`
  509. @tailwind utilities;
  510. `
  511. let output = css`
  512. .text-foo {
  513. color: hsl(217 91% 60% / var(--my-alpha));
  514. }
  515. `
  516. return run(input, {
  517. content: [{ raw: html`text-foo` }],
  518. corePlugins: { textOpacity: false },
  519. theme: {
  520. colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
  521. extend: {
  522. textColor: ({ theme }) => ({
  523. foo: theme('colors.blue.500 / var(--my-alpha)'),
  524. }),
  525. },
  526. },
  527. }).then((result) => {
  528. expect(result.css).toMatchFormattedCss(output)
  529. expect(result.warnings().length).toBe(0)
  530. })
  531. })
  532. test('Theme function in JS can apply alpha values to colors (7)', () => {
  533. let input = css`
  534. @tailwind utilities;
  535. `
  536. let output = css`
  537. .text-foo {
  538. color: rgb(var(--foo) / var(--my-alpha));
  539. }
  540. `
  541. return run(input, {
  542. content: [{ raw: html`text-foo` }],
  543. corePlugins: { textOpacity: false },
  544. theme: {
  545. colors: {
  546. blue: {
  547. 500: 'rgb(var(--foo) / <alpha-value>)',
  548. },
  549. },
  550. extend: {
  551. textColor: ({ theme }) => ({
  552. foo: theme('colors.blue.500 / var(--my-alpha)'),
  553. }),
  554. },
  555. },
  556. }).then((result) => {
  557. expect(result.css).toMatchFormattedCss(output)
  558. expect(result.warnings().length).toBe(0)
  559. })
  560. })
  561. test('Theme function prefers existing values in config', () => {
  562. let input = css`
  563. @tailwind utilities;
  564. `
  565. let output = css`
  566. .text-foo {
  567. color: purple;
  568. }
  569. `
  570. return run(input, {
  571. content: [{ raw: html`text-foo` }],
  572. corePlugins: { textOpacity: false },
  573. theme: {
  574. colors: {
  575. blue: {
  576. '500 / 50%': 'purple',
  577. },
  578. },
  579. extend: {
  580. textColor: ({ theme }) => ({
  581. foo: theme('colors.blue.500 / 50%'),
  582. }),
  583. },
  584. },
  585. }).then((result) => {
  586. expect(result.css).toMatchFormattedCss(output)
  587. expect(result.warnings().length).toBe(0)
  588. })
  589. })
  590. it('should be possible to use an <alpha-value> as part of the color definition', () => {
  591. let config = {
  592. content: [
  593. {
  594. raw: html` <div class="bg-primary"></div> `,
  595. },
  596. ],
  597. corePlugins: ['backgroundColor', 'backgroundOpacity'],
  598. theme: {
  599. colors: {
  600. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  601. },
  602. },
  603. }
  604. return run('@tailwind utilities', config).then((result) => {
  605. expect(result.css).toMatchFormattedCss(css`
  606. .bg-primary {
  607. --tw-bg-opacity: 1;
  608. background-color: rgb(var(--color-primary) / var(--tw-bg-opacity));
  609. }
  610. `)
  611. })
  612. })
  613. it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
  614. let config = {
  615. content: [
  616. {
  617. raw: html` <div class="bg-primary/50"></div> `,
  618. },
  619. ],
  620. corePlugins: ['backgroundColor', 'backgroundOpacity'],
  621. theme: {
  622. colors: {
  623. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  624. },
  625. },
  626. }
  627. return run('@tailwind utilities', config).then((result) => {
  628. expect(result.css).toMatchFormattedCss(css`
  629. .bg-primary\/50 {
  630. background-color: rgb(var(--color-primary) / 0.5);
  631. }
  632. `)
  633. })
  634. })
  635. it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
  636. let config = {
  637. content: [
  638. {
  639. raw: html` <div class="bg-primary"></div> `,
  640. },
  641. ],
  642. corePlugins: ['backgroundColor'],
  643. theme: {
  644. colors: {
  645. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  646. },
  647. },
  648. }
  649. return run('@tailwind utilities', config).then((result) => {
  650. expect(result.css).toMatchFormattedCss(css`
  651. .bg-primary {
  652. background-color: rgb(var(--color-primary) / 1);
  653. }
  654. `)
  655. })
  656. })
  657. it('should be possible to use <alpha-value> inside arbitrary values', () => {
  658. let config = {
  659. content: [
  660. {
  661. raw: html` <div class="bg-[rgb(var(--color-primary)/<alpha-value>)]/50"></div> `,
  662. },
  663. ],
  664. corePlugins: ['backgroundColor', 'backgroundOpacity'],
  665. theme: {
  666. colors: {
  667. primary: 'rgb(var(--color-primary) / <alpha-value>)',
  668. },
  669. },
  670. }
  671. return run('@tailwind utilities', config).then((result) => {
  672. expect(result.css).toMatchFormattedCss(css`
  673. .bg-\[rgb\(var\(--color-primary\)\/\<alpha-value\>\)\]\/50 {
  674. background-color: rgb(var(--color-primary) / 0.5);
  675. }
  676. `)
  677. })
  678. })
  679. it('Theme functions can reference values with slashes in brackets', () => {
  680. let config = {
  681. content: [
  682. {
  683. raw: html` <div class="bg-foo1 bg-foo2"></div> `,
  684. },
  685. ],
  686. theme: {
  687. colors: {
  688. 'a/b': '#000000',
  689. },
  690. extend: {
  691. backgroundColor: ({ theme }) => ({
  692. foo1: theme('colors[a/b]'),
  693. foo2: theme('colors[a/b]/50%'),
  694. }),
  695. },
  696. },
  697. }
  698. return run('@tailwind utilities', config).then((result) => {
  699. expect(result.css).toMatchFormattedCss(css`
  700. .bg-foo1 {
  701. --tw-bg-opacity: 1;
  702. background-color: rgb(0 0 0 / var(--tw-bg-opacity));
  703. }
  704. .bg-foo2 {
  705. background-color: #00000080;
  706. }
  707. `)
  708. })
  709. })
  710. it('works with opacity values defined as a placeholder or a function in when colors is a function', () => {
  711. let config = {
  712. content: [
  713. {
  714. raw: html`
  715. <div
  716. class="bg-foo10 bg-foo20 bg-foo30 bg-foo40 bg-foo11 bg-foo21 bg-foo31 bg-foo41"
  717. ></div>
  718. `,
  719. },
  720. ],
  721. theme: {
  722. colors: () => ({
  723. foobar1: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`,
  724. foobar2: `rgb(255 100 0 / <alpha-value>)`,
  725. foobar3: {
  726. 100: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`,
  727. 200: `rgb(255 100 0 / <alpha-value>)`,
  728. },
  729. }),
  730. extend: {
  731. backgroundColor: ({ theme }) => ({
  732. foo10: theme('colors.foobar1'),
  733. foo20: theme('colors.foobar2'),
  734. foo30: theme('colors.foobar3.100'),
  735. foo40: theme('colors.foobar3.200'),
  736. foo11: theme('colors.foobar1 / 50%'),
  737. foo21: theme('colors.foobar2 / 50%'),
  738. foo31: theme('colors.foobar3.100 / 50%'),
  739. foo41: theme('colors.foobar3.200 / 50%'),
  740. }),
  741. },
  742. },
  743. }
  744. return run('@tailwind utilities', config).then((result) => {
  745. expect(result.css).toMatchFormattedCss(css`
  746. .bg-foo10 {
  747. background-color: #ff6400;
  748. }
  749. .bg-foo11 {
  750. background-color: #ff640080;
  751. }
  752. .bg-foo20 {
  753. --tw-bg-opacity: 1;
  754. background-color: rgb(255 100 0 / var(--tw-bg-opacity));
  755. }
  756. .bg-foo21 {
  757. background-color: #ff640080;
  758. }
  759. .bg-foo30 {
  760. background-color: #ff6400;
  761. }
  762. .bg-foo31 {
  763. background-color: #ff640080;
  764. }
  765. .bg-foo40 {
  766. --tw-bg-opacity: 1;
  767. background-color: rgb(255 100 0 / var(--tw-bg-opacity));
  768. }
  769. .bg-foo41 {
  770. background-color: #ff640080;
  771. }
  772. `)
  773. })
  774. })
  775. it('The disableColorOpacityUtilitiesByDefault flag disables the color opacity plugins and removes their variables', () => {
  776. let config = {
  777. future: {
  778. disableColorOpacityUtilitiesByDefault: true,
  779. },
  780. content: [
  781. {
  782. raw: html`
  783. <div
  784. class="divide-blue-300 border-blue-300 bg-blue-300 text-blue-300 placeholder-blue-300 ring-blue-300"
  785. ></div>
  786. <div
  787. class="divide-blue-300/50 border-blue-300/50 bg-blue-300/50 text-blue-300/50 placeholder-blue-300/50 ring-blue-300/50"
  788. ></div>
  789. <div
  790. class="divide-blue-300/[var(--my-opacity)] border-blue-300/[var(--my-opacity)] bg-blue-300/[var(--my-opacity)] text-blue-300/[var(--my-opacity)] placeholder-blue-300/[var(--my-opacity)] ring-blue-300/[var(--my-opacity)]"
  791. ></div>
  792. <div
  793. class="divide-opacity-50 border-opacity-50 bg-opacity-50 text-opacity-50 placeholder-opacity-50 ring-opacity-50"
  794. ></div>
  795. `,
  796. },
  797. ],
  798. }
  799. return run('@tailwind utilities', config).then((result) => {
  800. expect(result.css).toMatchFormattedCss(css`
  801. .divide-blue-300 > :not([hidden]) ~ :not([hidden]) {
  802. border-color: #93c5fd;
  803. }
  804. .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) {
  805. border-color: #93c5fd80;
  806. }
  807. .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) {
  808. border-color: rgb(147 197 253 / var(--my-opacity));
  809. }
  810. .border-blue-300 {
  811. border-color: #93c5fd;
  812. }
  813. .border-blue-300\/50 {
  814. border-color: #93c5fd80;
  815. }
  816. .border-blue-300\/\[var\(--my-opacity\)\] {
  817. border-color: rgb(147 197 253 / var(--my-opacity));
  818. }
  819. .bg-blue-300 {
  820. background-color: #93c5fd;
  821. }
  822. .bg-blue-300\/50 {
  823. background-color: #93c5fd80;
  824. }
  825. .bg-blue-300\/\[var\(--my-opacity\)\] {
  826. background-color: rgb(147 197 253 / var(--my-opacity));
  827. }
  828. .text-blue-300 {
  829. color: #93c5fd;
  830. }
  831. .text-blue-300\/50 {
  832. color: #93c5fd80;
  833. }
  834. .text-blue-300\/\[var\(--my-opacity\)\] {
  835. color: rgb(147 197 253 / var(--my-opacity));
  836. }
  837. .placeholder-blue-300::placeholder {
  838. color: #93c5fd;
  839. }
  840. .placeholder-blue-300\/50::placeholder {
  841. color: #93c5fd80;
  842. }
  843. .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder {
  844. color: rgb(147 197 253 / var(--my-opacity));
  845. }
  846. .ring-blue-300 {
  847. --tw-ring-color: #93c5fd;
  848. }
  849. .ring-blue-300\/50 {
  850. --tw-ring-color: #93c5fd80;
  851. }
  852. .ring-blue-300\/\[var\(--my-opacity\)\] {
  853. --tw-ring-color: rgb(147 197 253 / var(--my-opacity));
  854. }
  855. `)
  856. })
  857. })
  858. it('You can re-enable any opacity plugin even when disableColorOpacityUtilitiesByDefault is enabled', () => {
  859. let config = {
  860. future: {
  861. disableColorOpacityUtilitiesByDefault: true,
  862. },
  863. corePlugins: {
  864. backgroundOpacity: true,
  865. borderOpacity: true,
  866. divideOpacity: true,
  867. placeholderOpacity: true,
  868. ringOpacity: true,
  869. textOpacity: true,
  870. },
  871. content: [
  872. {
  873. raw: html`
  874. <div
  875. class="divide-blue-300 border-blue-300 bg-blue-300 text-blue-300 placeholder-blue-300 ring-blue-300"
  876. ></div>
  877. <div
  878. class="divide-blue-300/50 border-blue-300/50 bg-blue-300/50 text-blue-300/50 placeholder-blue-300/50 ring-blue-300/50"
  879. ></div>
  880. <div
  881. class="divide-blue-300/[var(--my-opacity)] border-blue-300/[var(--my-opacity)] bg-blue-300/[var(--my-opacity)] text-blue-300/[var(--my-opacity)] placeholder-blue-300/[var(--my-opacity)] ring-blue-300/[var(--my-opacity)]"
  882. ></div>
  883. <div
  884. class="divide-opacity-50 border-opacity-50 bg-opacity-50 text-opacity-50 placeholder-opacity-50 ring-opacity-50"
  885. ></div>
  886. `,
  887. },
  888. ],
  889. }
  890. return run('@tailwind utilities', config).then((result) => {
  891. expect(result.css).toMatchFormattedCss(css`
  892. .divide-blue-300 > :not([hidden]) ~ :not([hidden]) {
  893. --tw-divide-opacity: 1;
  894. border-color: rgb(147 197 253 / var(--tw-divide-opacity));
  895. }
  896. .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) {
  897. border-color: #93c5fd80;
  898. }
  899. .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) {
  900. border-color: rgb(147 197 253 / var(--my-opacity));
  901. }
  902. .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) {
  903. --tw-divide-opacity: 0.5;
  904. }
  905. .border-blue-300 {
  906. --tw-border-opacity: 1;
  907. border-color: rgb(147 197 253 / var(--tw-border-opacity));
  908. }
  909. .border-blue-300\/50 {
  910. border-color: #93c5fd80;
  911. }
  912. .border-blue-300\/\[var\(--my-opacity\)\] {
  913. border-color: rgb(147 197 253 / var(--my-opacity));
  914. }
  915. .border-opacity-50 {
  916. --tw-border-opacity: 0.5;
  917. }
  918. .bg-blue-300 {
  919. --tw-bg-opacity: 1;
  920. background-color: rgb(147 197 253 / var(--tw-bg-opacity));
  921. }
  922. .bg-blue-300\/50 {
  923. background-color: #93c5fd80;
  924. }
  925. .bg-blue-300\/\[var\(--my-opacity\)\] {
  926. background-color: rgb(147 197 253 / var(--my-opacity));
  927. }
  928. .bg-opacity-50 {
  929. --tw-bg-opacity: 0.5;
  930. }
  931. .text-blue-300 {
  932. --tw-text-opacity: 1;
  933. color: rgb(147 197 253 / var(--tw-text-opacity));
  934. }
  935. .text-blue-300\/50 {
  936. color: #93c5fd80;
  937. }
  938. .text-blue-300\/\[var\(--my-opacity\)\] {
  939. color: rgb(147 197 253 / var(--my-opacity));
  940. }
  941. .text-opacity-50 {
  942. --tw-text-opacity: 0.5;
  943. }
  944. .placeholder-blue-300::placeholder {
  945. --tw-placeholder-opacity: 1;
  946. color: rgb(147 197 253 / var(--tw-placeholder-opacity));
  947. }
  948. .placeholder-blue-300\/50::placeholder {
  949. color: #93c5fd80;
  950. }
  951. .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder {
  952. color: rgb(147 197 253 / var(--my-opacity));
  953. }
  954. .placeholder-opacity-50::placeholder {
  955. --tw-placeholder-opacity: 0.5;
  956. }
  957. .ring-blue-300 {
  958. --tw-ring-opacity: 1;
  959. --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity));
  960. }
  961. .ring-blue-300\/50 {
  962. --tw-ring-color: #93c5fd80;
  963. }
  964. .ring-blue-300\/\[var\(--my-opacity\)\] {
  965. --tw-ring-color: rgb(147 197 253 / var(--my-opacity));
  966. }
  967. .ring-opacity-50 {
  968. --tw-ring-opacity: 0.5;
  969. }
  970. `)
  971. })
  972. })
  973. it('can replace the potential alpha value in rgba/hsla syntax', async () => {
  974. let config = {
  975. content: [{ raw: html` <div class="text-primary-rgba/50 text-primary-hsla/50"></div> ` }],
  976. theme: {
  977. colors: {
  978. 'primary-rgba': 'rgba(var(--color), 0.1)',
  979. 'primary-hsla': 'hsla(var(--color), 0.1)',
  980. },
  981. },
  982. }
  983. let result = await run('@tailwind utilities', config)
  984. expect(result.css).toMatchFormattedCss(css`
  985. .text-primary-hsla\/50 {
  986. color: hsla(var(--color), 0.5);
  987. }
  988. .text-primary-rgba\/50 {
  989. color: rgba(var(--color), 0.5);
  990. }
  991. `)
  992. })
  993. it('variables with variable fallback values can use opacity modifier', async () => {
  994. let config = {
  995. content: [
  996. {
  997. raw: html`<div class="bg-[rgb(var(--some-var,var(--some-other-var)))]/50"></div>`,
  998. },
  999. ],
  1000. }
  1001. let result = await run(`@tailwind utilities;`, config)
  1002. expect(result.css).toMatchFormattedCss(css`
  1003. .bg-\[rgb\(var\(--some-var\,var\(--some-other-var\)\)\)\]\/50 {
  1004. background-color: rgb(var(--some-var, var(--some-other-var)) / 0.5);
  1005. }
  1006. `)
  1007. })