Skip to content

Commit b7ca16a

Browse files
authored
feat: new namespace / namespaceDelimiter options (#36)
`prefix` options becomes **deprecated**.
1 parent ec585da commit b7ca16a

File tree

4 files changed

+137
-19
lines changed

4 files changed

+137
-19
lines changed

README.md

+41-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,46 @@ b('element', { mod: true })
6262
//=> 'block__element-mod'
6363
```
6464

65+
### `namespace = ''`
66+
67+
```ts
68+
const b = block('block', { namespace: 'ns' })
69+
70+
b()
71+
//=> 'ns-block'
72+
73+
b('element', { mod1: true, mod2: true })
74+
//=> 'ns-block__element--mod1 ns-block__element--mod2'
75+
```
76+
77+
### `namespaceDelimiter = '-'`
78+
79+
```ts
80+
const b = block('block', { namespace: 'ns', namespaceDelimiter: '---' })
81+
82+
b()
83+
//=> 'ns---block'
84+
85+
b('element', { mod1: true, mod2: true })
86+
//=> 'ns---block__element--mod1 ns---block__element--mod2'
87+
```
88+
89+
When `namespace` is not given, `namespaceDelimiter` will be ignored.
90+
91+
```ts
92+
const b = block('block', { namespaceDelimiter: '---' })
93+
94+
b()
95+
//=> 'block'
96+
97+
b('element', { mod1: true, mod2: true })
98+
//=> 'block__element--mod1 block__element--mod2'
99+
```
100+
65101
### `prefix = ''`
66102

103+
**[DEPRECATED]**: Please use `namespace` and `namespaceDelimiter`.
104+
67105
```ts
68106
const b = block('block', { prefix: 'pre---' })
69107

@@ -84,13 +122,14 @@ import block, { setup } from 'bem-ts'
84122
setup({
85123
elementDelimiter: '_',
86124
modifierDelimiter: '-',
87-
prefix: 'pre---'
125+
namespace: 'ns',
126+
namespaceDelimiter: '---'
88127
})
89128

90129
const b = block('block')
91130

92131
b('element', { mod: true })
93-
//=> 'pre---block_element-mod'
132+
//=> 'ns---block_element-mod'
94133
```
95134

96135
## Install

index.ts

+27-5
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,31 @@ type Modifiers = { [key: string]: boolean; }
33
const defaults = {
44
elementDelimiter: '__',
55
modifierDelimiter: '--',
6+
namespace: '',
7+
namespaceDelimiter: '-',
68
prefix: '',
79
}
810

9-
export function setup(options: { elementDelimiter?: string, modifierDelimiter?: string, prefix?: string }) {
10-
if (options.elementDelimiter) {
11+
export function setup(options: {
12+
elementDelimiter?: string,
13+
modifierDelimiter?: string,
14+
namespace?: string,
15+
namespaceDelimiter?: string,
16+
prefix?: string,
17+
}) {
18+
if (typeof options.elementDelimiter === 'string') {
1119
defaults.elementDelimiter = options.elementDelimiter
1220
}
13-
if (options.modifierDelimiter) {
21+
if (typeof options.modifierDelimiter === 'string') {
1422
defaults.modifierDelimiter = options.modifierDelimiter
1523
}
16-
if (options.prefix) {
24+
if (typeof options.namespace === 'string') {
25+
defaults.namespace = options.namespace
26+
}
27+
if (typeof options.namespaceDelimiter === 'string') {
28+
defaults.namespaceDelimiter = options.namespaceDelimiter
29+
}
30+
if (typeof options.prefix === 'string') {
1731
defaults.prefix = options.prefix
1832
}
1933
}
@@ -23,11 +37,19 @@ export default function bem(
2337
{
2438
elementDelimiter = defaults.elementDelimiter,
2539
modifierDelimiter = defaults.modifierDelimiter,
40+
namespace = defaults.namespace,
41+
namespaceDelimiter = defaults.namespaceDelimiter,
2642
prefix = defaults.prefix,
2743
} = {},
2844
) {
2945
return (elementOrModifiers?: string | Modifiers, modifiers?: Modifiers) => {
30-
let base = `${prefix}${block}`
46+
if (namespace && prefix) {
47+
throw new TypeError(`prefix('${prefix}') is deprecated. Use namespace('${namespace}') instead.`)
48+
}
49+
50+
const nsDelim = namespace ? namespaceDelimiter : ''
51+
const pre = prefix || `${namespace}${nsDelim}`
52+
let base = `${pre}${block}`
3153

3254
if (!elementOrModifiers) {
3355
return base

test.ts

+68-11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,42 @@ const testCases = [
3737
'block__element-mod1 block__element-mod2',
3838
],
3939
},
40+
{
41+
description: '`namespace` option',
42+
tested: () => block('block', { namespace: 'ns' }),
43+
expectations: [
44+
'ns-block',
45+
'ns-block--mod1',
46+
'ns-block--mod1 ns-block--mod2',
47+
'ns-block__element',
48+
'ns-block__element--mod1',
49+
'ns-block__element--mod1 ns-block__element--mod2',
50+
],
51+
},
52+
{
53+
description: '`namespaceDelimiter` option',
54+
tested: () => block('block', { namespace: 'ns', namespaceDelimiter: '---' }),
55+
expectations: [
56+
'ns---block',
57+
'ns---block--mod1',
58+
'ns---block--mod1 ns---block--mod2',
59+
'ns---block__element',
60+
'ns---block__element--mod1',
61+
'ns---block__element--mod1 ns---block__element--mod2',
62+
],
63+
},
64+
{
65+
description: '`namespaceDelimiter` option without `namespace` option',
66+
tested: () => block('block', { namespaceDelimiter: '---' }),
67+
expectations: [
68+
'block',
69+
'block--mod1',
70+
'block--mod1 block--mod2',
71+
'block__element',
72+
'block__element--mod1',
73+
'block__element--mod1 block__element--mod2',
74+
],
75+
},
4076
{
4177
description: '`prefix` option',
4278
tested: () => block('block', { prefix: 'pre---' }),
@@ -55,17 +91,19 @@ const testCases = [
5591
setup({
5692
elementDelimiter: '_',
5793
modifierDelimiter: '-',
58-
prefix: 'pre---',
94+
namespace: 'ns',
95+
namespaceDelimiter: '---',
96+
// prefix: 'pre---',
5997
})
6098
return block('block')
6199
},
62100
expectations: [
63-
'pre---block',
64-
'pre---block-mod1',
65-
'pre---block-mod1 pre---block-mod2',
66-
'pre---block_element',
67-
'pre---block_element-mod1',
68-
'pre---block_element-mod1 pre---block_element-mod2',
101+
'ns---block',
102+
'ns---block-mod1',
103+
'ns---block-mod1 ns---block-mod2',
104+
'ns---block_element',
105+
'ns---block_element-mod1',
106+
'ns---block_element-mod1 ns---block_element-mod2',
69107
],
70108
},
71109
]
@@ -104,14 +142,33 @@ testCases.forEach(({ description, tested, expectations }) => {
104142
})
105143
})
106144

107-
describe('`setup()` additional cases', () => {
145+
describe('`namespace` and `prefix` at the same time', () => {
146+
it('throws `TypeError`', () => {
147+
const b = block('block', { namespace: 'ns', prefix: 'pre' })
148+
expect(() => b()).toThrow(TypeError)
149+
expect(() => b()).toThrow("prefix('pre') is deprecated. Use namespace('ns') instead.")
150+
})
151+
})
152+
153+
// `setup()` test must be at last
154+
describe('`setup()` additional case', () => {
108155
it('overrides options which was setup', () => {
109-
const b = block('block', { elementDelimiter: ':', modifierDelimiter: '/', prefix: 'p-' })
110-
expect(b('element', { mod: true })).toBe('p-block:element/mod')
156+
const b = block('block', {
157+
elementDelimiter: ':',
158+
modifierDelimiter: '/',
159+
namespace: 'n',
160+
namespaceDelimiter: '=',
161+
})
162+
expect(b('element', { mod: true })).toBe('n=block:element/mod')
111163
})
112164

113165
it('has no effect when empty options are passed', () => {
114166
setup({})
115-
expect(block('block')('element', { mod: true })).toBe('pre---block_element-mod')
167+
expect(block('block')('element', { mod: true })).toBe('ns---block_element-mod')
168+
})
169+
170+
it('`prefix` option [deprecated]', () => {
171+
setup({ prefix: 'pre:', namespace: '' })
172+
expect(block('block')('element', { mod: true })).toBe('pre:block_element-mod')
116173
})
117174
})

tslint.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"rules": {
55
"interface-over-type-literal": false,
66
"object-literal-sort-keys": false,
7-
"quotemark": [true, "single"],
7+
"quotemark": [true, "single", "avoid-escape"],
88
"semicolon": [true, "never"]
99
}
1010
}

0 commit comments

Comments
 (0)