Skip to content

typescript version inside #102

@jeremy-coleman

Description

@jeremy-coleman

better editor feedback without being aidsy than pretty much every other style library (at least imo)

import React from 'react'
import { HTMLProps, CSSProperties } from 'react'
const h = React.createElement

//new CSSRuleList() //items, length
//let r = new CSSStyleRule

//was using this like this, jus took context out though idk, deal later
//{theme: defined(context.theme, props.theme, pallete: 'none')}
const defined = (...args) => {
  for (var i = 0; i < args.length; i++) {
    if (args[i] !== undefined) return args[i]
  }
}

let cache = {}
let prefix = 'x'
const rules: CSSStyleRule[] = [] //[]

let insert = (rule: CSSStyleRule) => void rules.push(rule as CSSStyleRule)

const hyph = s => s.replace(/[A-Z]|^ms/g, '-$&').toLowerCase()
const mx = (rule, media) => (media ? `${media}{${rule}}` : rule)
const rx = (cn, prop, val) => `.${cn}{${hyph(prop)}:${val}}`
const noAnd = s => s.replace(/&/g, '')

const parse = (obj, child = '', media?) =>
  Object.keys(obj)
    .map(key => {
      const val = obj[key]
      if (val === null) return ''
      if (typeof val === 'object') {
        const m2 = /^@/.test(key) ? key : null
        const c2 = m2 ? child : child + key
        return parse(val, c2, m2 || media)
      }
      const _key = key + val + child + media
      if (cache[_key]) return cache[_key]
      const className = prefix + rules.length.toString(36)
      insert(mx(rx(className + noAnd(child), key, val), media))
      cache[_key] = className
      return className
    })
    .join(' ')

function cxs(...styles) {
  return styles
    .map(style => parse(style))
    .join(' ')
    .trim()
}

cxs.css = () => rules.sort().join('')

cxs.reset = () => {
  cache = {}
  while (rules.length) rules.pop()
}

cxs.prefix = val => (prefix = val)

if (typeof document !== 'undefined') {
  const sheet = document.head.appendChild(document.createElement('style')).sheet as CSSStyleSheet
  insert = (rule: CSSStyleRule & string) => {
    rules.push(rule as CSSStyleRule)
    sheet.insertRule(rule, sheet.cssRules.length)
  }
}

type DomProps = Partial<HTMLProps<any>>
type CSX = { css?: CSSProperties }
type StyledCSX = DomProps & CSX

type Proptional<P> = CSSProperties | ((...args: P[]) => CSSProperties)

function styled<P>(C) {
  return (...args: Proptional<P>[]) => {
    const Comp = (props: P & StyledCSX) => {
      const stylePropKeys = [...Object.keys({}), 'css']
      //const styleProps = Object.assign({ theme: defined(context.theme, props.theme, {}) }, props)

      const next: any = {}
      for (let key in props) {
        if (stylePropKeys.includes(key)) continue
        next[key] = props[key]
      }
      next.className = [
        next.className,
        ...args
          .map(proptional => (typeof proptional === 'function' ? proptional(props) : proptional))
          .filter(s => !!s)
          .map(s => cxs(s)),
        cxs(props.css || {}),
      ]
        .join(' ')
        .trim()

      return h(C, next)
    }

    return Comp
  }
}

styled.css = cxs.css
styled.reset = cxs.reset

export { cxs }
export { styled }
export default styled

// export function styledComponentWithProps<T, U extends HTMLElement = HTMLElement>(styledFunction: StyledFunction<React.HTMLProps<U>>): StyledFunction<T & React.HTMLProps<U>> {
//   return styledFunction as any;
// }

// thanks microsoft, please teach our youth how to read, i think you've got it figured out
// type Unpacked<T> = T extends (infer U)[]
//   ? U
//   : T extends (...args: any[]) => infer U
//   ? U
//   : T extends Promise<infer U>
//   ? U
//   : T

// type T0 = Unpacked<string> // string
// type T1 = Unpacked<string[]> // string
// type T2 = Unpacked<() => string> // string

// type Foo<T> = T extends { a: infer U; b: infer U } ? U : never
// type T10 = Foo<{ a: string; b: string }> // string
// type T11 = Foo<{ a: string; b: number }> // string | number

//type CC = (...args: CSSProperties[]) => infer R ? R : CSSProperties

//type ReturnType<T> = (...args) => T ? T : CSSProperties
// im going to space mountain charley fml

// function styled1(C) {
//   return (...args) => {
//     const Comp = (props, context: any = {}) => {
//       const stylePropKeys = [...Object.keys({}), 'css']
//       const styleProps = Object.assign({ theme: defined(context.theme, props.theme, {}) }, props)

//       const next: any = {}
//       for (let key in props) {
//         if (stylePropKeys.includes(key)) continue
//         next[key] = props[key]
//       }
//       next.className = [
//         next.className,
//         ...args
//           .map(a => (typeof a === 'function' ? a(styleProps) : a))
//           .filter(s => !!s)
//           .map(s => cxs(s)),
//         cxs(props.css || {}),
//       ]
//         .join(' ')
//         .trim()

//       return h(C, next)
//     }

//     return Comp
//   }
// }

usage

import React from 'react'
import { styled } from './styled'

type Props = {
  color: 'green' | 'black'
}

let MyButton = styled<Props>('button')(props => ({
  backgroundColor: (props.color && props.color) || 'green',
}))

let NoPropsButton = styled('button')({
  backgroundColor: 'green',
})

export { MyButton, NoPropsButton }


let Demo = props => <MyButton onClick={e => console.log('hi')} color={'black'}/>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions