Minimal styling, powered by Goober.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

144 lignes
2.9 KiB

  1. import { css as gooberCss } from 'goober';
  2. import { PropertiesHyphenFallback } from 'csstype';
  3. interface CssString {
  4. // TODO stricter type checking
  5. toString(): string
  6. }
  7. export class CssStringImpl implements CssString {
  8. private css: string
  9. constructor(s: TemplateStringsArray) {
  10. this.css = s.raw[0]
  11. .trim()
  12. .replace(/[ ][ ]+/g, ' ')
  13. .replace(/:[ ]/g, ':')
  14. .replace(/\n/g, '')
  15. .replace(/;[ ]/g, ';');
  16. }
  17. toString() {
  18. return this.css
  19. }
  20. }
  21. interface CssIf {
  22. (b: boolean): (...a: CssString[]) => CssIfString
  23. }
  24. interface CssElse {
  25. (...c: CssString[]): CssString
  26. if: CssIf
  27. }
  28. interface CssIfString extends CssString {
  29. else: CssElse
  30. }
  31. const cssIf: CssIf = (b: boolean) => (...a: CssString[]) => new CssIfStringImpl(b, ...a);
  32. export class CssIfStringImpl implements CssIfString {
  33. readonly else: CssElse
  34. private readonly cssStrings: CssString[]
  35. constructor(private readonly condition: boolean, ...cssStrings: CssString[]) {
  36. this.cssStrings = cssStrings
  37. const elseFn = (...c: CssString[]) => {
  38. if (this.condition) {
  39. return {
  40. toString: () => {
  41. return this.cssStrings.map((c2) => c2.toString()).join('');
  42. }
  43. }
  44. }
  45. return {
  46. toString: () => {
  47. return c.map((cc) => cc.toString()).join('')
  48. }
  49. };
  50. }
  51. elseFn.if = cssIf
  52. this.else = elseFn
  53. }
  54. toString() {
  55. if (this.condition) {
  56. return this.cssStrings.map((c2) => c2.toString()).join('');
  57. }
  58. return '';
  59. }
  60. }
  61. interface CssNest {
  62. (selector: string): (...a: CssString[]) => CssString
  63. }
  64. const cssNest: CssNest = (selector) => (...a) => {
  65. return {
  66. toString: () => `${selector}{${a.map(aa => aa.toString()).join('')}}`
  67. }
  68. }
  69. interface CssDynamic {
  70. (a: PropertiesHyphenFallback): CssString
  71. }
  72. const cssDynamic: CssDynamic = (a: PropertiesHyphenFallback) => {
  73. return {
  74. toString(): string {
  75. return Object
  76. .entries(a)
  77. .map(([key, value]) => `${key}:${value.toString()};`)
  78. .join('')
  79. }
  80. };
  81. };
  82. interface CssMedia {
  83. (raw: string): any
  84. }
  85. const cssMedia: CssMedia = (arg1: string) => {
  86. return (...body: CssString[]) => {
  87. return {
  88. toString(): string {
  89. return `@media ${arg1}{${body.map(b => b.toString()).join('')}}`
  90. }
  91. }
  92. }
  93. }
  94. const cssCompile = (...strings: CssString[]) => {
  95. return strings
  96. .filter((s) => ['string', 'object'].includes(typeof s))
  97. .map((s) => {
  98. if (typeof s === 'object') {
  99. return gooberCss`${s.toString()}`
  100. }
  101. return s
  102. })
  103. .join(' ')
  104. }
  105. interface Css {
  106. (s: TemplateStringsArray): CssString
  107. if: CssIf
  108. nest: CssNest
  109. dynamic: CssDynamic
  110. media: CssMedia
  111. cx(...strings: CssString[]): string
  112. }
  113. const _css: Partial<Css> = (s: TemplateStringsArray) => new CssStringImpl(s);
  114. _css.if = cssIf;
  115. _css.nest = cssNest;
  116. _css.dynamic = cssDynamic;
  117. _css.media = cssMedia;
  118. _css.cx = cssCompile;
  119. export const css = _css as Css;