opacity.test.js 28 KB

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