Passed
Push — main ( ddcd3f...98b49f )
by Andrii
02:26
created

ctx.ts ➔ classNamingCtx   A

Complexity

Conditions 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 14
c 0
b 0
f 0
rs 10
cc 1
1
import type { ToggleMap, ClassNamer, ClassNamed, ClassNamesMap, EmptyObject } from "./defs"
2
import {dehash, joinWithLead, truthyKeys, wrapper} from "./core"
3
import { emptize } from "./utils"
4
import { EMPTY_OBJECT } from "./consts"
5
6
emptize(classNamer)
7
8
//TODO no `className` - no first `true`
9
interface tClassNaming<
10
  ClassKeys extends string,
11
  withClassNames extends boolean | undefined
12
> {
13
  /**
14
   * @example classes(true) === props.className
15
   * @example classes({class1: true, class2: false}) === "class1"
16
   * @example classes(true, {class1: true, class2: false})
17
  */
18
 // Using overloads will make error not in certain argument but on all call - 'No overload found'
19
  (
20
    propagate_or_map_or_expression?: true | ToggleMap<ClassKeys>,
21
    map_or_expression?: [Extract<typeof propagate_or_map_or_expression, true>] extends [never]
22
    ? never
23
    : ToggleMap<ClassKeys>
24
  ) : ClassNamed & (
25
    withClassNames extends true
26
    ? {classnames: ClassNamesMap<ClassKeys>}
27
    : EmptyObject
28
  ) 
29
}
30
31
export default classNamingCtx
32
33
/**
34
 * @example const classes = classNamingCtx(this.props)
35
 * @example const classes = classNamingCtx({className, classnames})
36
 * @example const classes = classNamingCtx({classnames})
37
 */
38
function classNamingCtx<
39
  ClassKeys extends string,
40
  withClassNames extends boolean|undefined
41
>(
42
  {classnames, className}: ClassNamer<ClassKeys>,
43
  options: Readonly<ClassNamerOptions<withClassNames>> = EMPTY_OBJECT
44
) {
45
  return classNamer.bind({classnames, className, options, stacked: undefined}) as tClassNaming<ClassKeys, withClassNames>
46
}
47
48
type ClassNamerOptions<
49
  withClassNames extends undefined|boolean
50
> = Partial<{
51
  withClassNames: withClassNames
52
  // withSelf: boolean
53
}>
54
55
function classNamer<
56
  ClassKeys extends string,
57
  withClassNames extends boolean|undefined
58
>(
59
  this: ClassNamer<ClassKeys> & {
60
    options: Readonly<ClassNamerOptions<withClassNames>>
61
    stacked: string|undefined
62
  },
63
  arg0?: true | ToggleMap<ClassKeys>,
64
  arg1?: typeof arg0 extends true ? ToggleMap<ClassKeys> : never,
65
): ClassNamed & Partial<Pick<typeof this, "classnames">> {
66
  const {
67
    className: propagated,
68
    classnames,
69
    stacked: preStacked,
70
    options
71
  } = this
72
  , {
73
    withClassNames,
74
    // withSelf
75
  } = options
76
  , withPropagation = arg0 === true
77
  , allowed: ClassKeys[] = truthyKeys(arg0 === true ? arg1 : arg0)
78
  //@ts-expect-error
79
  .filter<ClassKeys>(
80
    Boolean
81
  )
82
  
83
  emptize(classnames)
84
85
  classnames && dehash(classnames, allowed)
86
  
87
  const stacked = joinWithLead(preStacked, allowed)
88
  , className = joinWithLead(withPropagation && propagated, stacked)
89
  , host = classNamer.bind({classnames, className, options, stacked})
90
91
  withClassNames && (
92
    //@ts-expect-error
93
    host["classnames"] = classnames
94
  )
95
  return wrapper(
96
    host,
97
    className,
98
  )
99
}