simple-merge-class-names 9.0.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -354
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,84 +1,38 @@
|
|
|
1
|
-
#
|
|
1
|
+
- [Why this package exists](#why-this-package-exists)
|
|
2
|
+
- [Why not `clsx`](#why-not-clsx)
|
|
3
|
+
- [Exported functions](#exported-functions)
|
|
4
|
+
- [Quick start](#quick-start)
|
|
5
|
+
- [Valid arguments](#valid-arguments)
|
|
6
|
+
- [Invalid arguments](#invalid-arguments)
|
|
7
|
+
- [Github](#github)
|
|
8
|
+
- [License](#license)
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
# Why this package exists
|
|
4
11
|
|
|
5
|
-
|
|
12
|
+
I got tired of squinting at the single line TailwindCSS `className = "..." ` string cramming a dozen utility classes with no delimiter between them, so I organically created a function that would split each string on a new line, and merge them back.
|
|
6
13
|
|
|
7
|
-
|
|
14
|
+
# Why not `clsx`
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
- [Table of Contents](#table-of-contents)
|
|
11
|
-
- [Stop Starving Gaza](#stop-starving-gaza)
|
|
12
|
-
- [Install](#install)
|
|
13
|
-
- [Install `Prettier` too](#install-prettier-too)
|
|
14
|
-
- [Exported Functions](#exported-functions)
|
|
15
|
-
- [Non-scale Usage](#non-scale-usage)
|
|
16
|
-
- [Example](#example)
|
|
17
|
-
- [Scale Usage](#scale-usage)
|
|
18
|
-
- [Create intermediary `@/mergeClassNames.js`](#create-intermediary-mergeclassnamesjs)
|
|
19
|
-
- [Project Structure](#project-structure)
|
|
20
|
-
- [Enable `@`-style Imports in Vite](#enable--style-imports-in-vite)
|
|
21
|
-
- [Example](#example-1)
|
|
22
|
-
- [During Dev, Debug Entire Project](#during-dev-debug-entire-project)
|
|
23
|
-
- [Valid Arguments](#valid-arguments)
|
|
24
|
-
- [Example](#example-2)
|
|
25
|
-
- [Invalid Arguments](#invalid-arguments)
|
|
26
|
-
- [Example](#example-3)
|
|
27
|
-
- [Developer Console Warnings](#developer-console-warnings)
|
|
28
|
-
- [Conditional Class Inclusion](#conditional-class-inclusion)
|
|
29
|
-
- [Avoid Short-circuit Syntax](#avoid-short-circuit-syntax)
|
|
30
|
-
- [Return Result](#return-result)
|
|
31
|
-
- [Example](#example-4)
|
|
32
|
-
- [Side Effect](#side-effect)
|
|
33
|
-
- [Example](#example-5)
|
|
34
|
-
- [Chaining](#chaining)
|
|
35
|
-
- [Usage of Browser Debugger](#usage-of-browser-debugger)
|
|
36
|
-
- [Testing Source Code](#testing-source-code)
|
|
37
|
-
- [Run Once](#run-once)
|
|
38
|
-
- [Run Watch Mode](#run-watch-mode)
|
|
39
|
-
- [License](#license)
|
|
16
|
+
I didn't like the unreadable [code](https://github.com/lukeed/clsx/blob/master/src/index.js) and the fact it accepts all types of arguments. I thought my engineering approach is better both in terms of code readability and strictness.
|
|
40
17
|
|
|
41
|
-
|
|
18
|
+
I used TypeScript and a functional programming approach to develop it.
|
|
42
19
|
|
|
43
|
-
|
|
20
|
+
# Exported functions
|
|
44
21
|
|
|
45
|
-
|
|
22
|
+
| | Warns | Invokes debugger |
|
|
23
|
+
| ----------------------------- | ------ | ---------------- |
|
|
24
|
+
| `mergeClassNames` | ✅ | ❌ |
|
|
25
|
+
| `mergeClassNamesDebugger` | ✅ | ✅ |
|
|
26
|
+
| `createCustomMergeClassNames` | Custom | Custom |
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- [Legal Action](https://www.hindrajabfoundation.org/perpetrators)
|
|
50
|
-
|
|
51
|
-
## Install
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
pnpm add simple-merge-class-names
|
|
55
|
-
|
|
56
|
-
# or
|
|
57
|
-
yarn add simple-merge-class-names
|
|
58
|
-
|
|
59
|
-
# or
|
|
60
|
-
npm install simple-merge-class-names
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Install `Prettier` too
|
|
64
|
-
|
|
65
|
-
[https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
|
66
|
-
|
|
67
|
-
It will nicely format and split your classes across new lines, and alleviate wrist strain because you will use single quotes (single key) instead of double (2 keys).
|
|
68
|
-
|
|
69
|
-
## Exported Functions
|
|
70
|
-
|
|
71
|
-
| | `console.warn`s | Invokes JS `debugger;` statement on invalid arguments, which pauses execution when Debugger is attached |
|
|
72
|
-
| ------------------------- | --------------- | ------------------------------------------------------------------------------------------------------- |
|
|
73
|
-
| `mergeClassNames` | ✅ | ❌ |
|
|
74
|
-
| `mergeClassNamesDebugger` | ✅ | ✅ |
|
|
75
|
-
|
|
76
|
-
## Non-scale Usage
|
|
77
|
-
|
|
78
|
-
### Example
|
|
28
|
+
# Quick start
|
|
79
29
|
|
|
80
30
|
```jsx
|
|
81
|
-
|
|
31
|
+
/*
|
|
32
|
+
{
|
|
33
|
+
"fileName": "App.jsx"
|
|
34
|
+
}
|
|
35
|
+
*/
|
|
82
36
|
import { mergeClassNames } from "simple-merge-class-names";
|
|
83
37
|
|
|
84
38
|
const Component = ({ condition }) => {
|
|
@@ -98,301 +52,34 @@ const Component = ({ condition }) => {
|
|
|
98
52
|
};
|
|
99
53
|
```
|
|
100
54
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-

|
|
104
|
-
|
|
105
|
-
### Create intermediary `@/mergeClassNames.js`
|
|
106
|
-
|
|
107
|
-
#### Project Structure
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
my-react-app/
|
|
111
|
-
├─ src/
|
|
112
|
-
│ ├─ components/
|
|
113
|
-
│ ├─ mergeClassNames.js // <- create it here
|
|
114
|
-
│ ├─ App.jsx
|
|
115
|
-
│ └─ index.js
|
|
116
|
-
├─ package.json
|
|
117
|
-
├─ vite.config.js
|
|
118
|
-
└─ README.md
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### Enable `@`-style Imports in Vite
|
|
122
|
-
|
|
123
|
-
`@` points to `my-react-app/src`
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
// vite.config.js
|
|
127
|
-
|
|
128
|
-
import { defineConfig } from "vite";
|
|
129
|
-
import react from "@vitejs/plugin-react";
|
|
130
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
131
|
-
import path from "path";
|
|
132
|
-
|
|
133
|
-
// https://vitejs.dev/config/
|
|
134
|
-
export default defineConfig({
|
|
135
|
-
plugins: [react(), tailwindcss()],
|
|
136
|
-
|
|
137
|
-
resolve: {
|
|
138
|
-
alias: {
|
|
139
|
-
"@": path.resolve(__dirname, "src"), // @ now points to "my-react-app/src"
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
```js
|
|
146
|
-
// src/mergeClassNames.js
|
|
147
|
-
|
|
148
|
-
export { mergeClassNames } from "simple-merge-class-names";
|
|
149
|
-
|
|
150
|
-
// export { mergeClassNames as mergeClassNamesDebugger } from "simple-merge-class-names";
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
And toggle-comment between the first and second lines as needed.
|
|
154
|
-
|
|
155
|
-
### Example
|
|
156
|
-
|
|
157
|
-
#### During Dev, Debug Entire Project
|
|
158
|
-
|
|
159
|
-
```js
|
|
160
|
-
// @/mergeClassNames.js
|
|
161
|
-
|
|
162
|
-
// export { mergeClassNames } from "simple-merge-class-names";
|
|
163
|
-
|
|
164
|
-
export { mergeClassNames as mergeClassNamesDebugger } from "simple-merge-class-names";
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
```jsx
|
|
168
|
-
// @/App.jsx
|
|
169
|
-
|
|
170
|
-
import { mergeClassNames } from "@/mergeClassNames.js";
|
|
171
|
-
|
|
172
|
-
const Component = ({ condition }) => {
|
|
173
|
-
return (
|
|
174
|
-
<div
|
|
175
|
-
className={mergeClassNames(
|
|
176
|
-
"app",
|
|
177
|
-
condition ? "min-h-dvh" : false,
|
|
178
|
-
"grid",
|
|
179
|
-
"grid-rows-[auto_1fr_auto]",
|
|
180
|
-
"outline",
|
|
181
|
-
)}
|
|
182
|
-
>
|
|
183
|
-
Hello, world!
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
};
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## Valid Arguments
|
|
55
|
+
# Valid arguments
|
|
190
56
|
|
|
191
|
-
|
|
57
|
+
Valid arguments are:
|
|
192
58
|
|
|
193
|
-
1.
|
|
194
|
-
2.
|
|
59
|
+
1. `string`s, that are not fully whitespace, these will be the class names you pass.
|
|
60
|
+
2. Empty string `""`
|
|
61
|
+
3. `null`
|
|
62
|
+
4. `undefined`
|
|
63
|
+
5. `false`
|
|
195
64
|
|
|
196
|
-
|
|
65
|
+
The latter four are valid but will be ignored as they're commonly used in conditional expressions.
|
|
197
66
|
|
|
198
|
-
|
|
199
|
-
mergeClassNames(
|
|
200
|
-
condition ? "daisy-btn-active" : false
|
|
201
|
-
"mx-auto",
|
|
202
|
-
"min-dvh ",
|
|
203
|
-
" flex",
|
|
204
|
-
" grid ",
|
|
205
|
-
"italic font-bold ",
|
|
206
|
-
`
|
|
207
|
-
gap-y-4
|
|
208
|
-
`,
|
|
209
|
-
);
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Invalid Arguments
|
|
67
|
+
# Invalid arguments
|
|
213
68
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
- Invalid strings:
|
|
217
|
-
- Empty strings: _(`""`)_
|
|
218
|
-
- Fully whitespace strings: any consecutive combination of the following:
|
|
219
|
-
- new lines,
|
|
220
|
-
- spaces,
|
|
221
|
-
- tabs
|
|
222
|
-
- _(e.g. `" "`, `"\n "`, `" \t \n "`, etc.)_
|
|
223
|
-
- `true`
|
|
224
|
-
- `undefined`
|
|
225
|
-
- `null`
|
|
69
|
+
- Fully whitespace strings
|
|
226
70
|
- Objects
|
|
227
|
-
-
|
|
228
|
-
-
|
|
71
|
+
- Arrays
|
|
72
|
+
- `true`
|
|
229
73
|
- Symbols
|
|
230
74
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
### Example
|
|
75
|
+
These will cause a console warning to be printed to alert you something might be off.
|
|
234
76
|
|
|
235
|
-
|
|
236
|
-
const someVariable = "";
|
|
237
|
-
|
|
238
|
-
mergeClassNames(
|
|
239
|
-
someVariable,
|
|
240
|
-
" ",
|
|
241
|
-
"\n ",
|
|
242
|
-
" \t \n ",
|
|
243
|
-
`
|
|
244
|
-
\n
|
|
245
|
-
`,
|
|
246
|
-
true,
|
|
247
|
-
undefined,
|
|
248
|
-
null,
|
|
249
|
-
{
|
|
250
|
-
name: "name",
|
|
251
|
-
email: "name@example.com",
|
|
252
|
-
},
|
|
253
|
-
123,
|
|
254
|
-
123.45,
|
|
255
|
-
);
|
|
256
|
-
```
|
|
77
|
+
# Github
|
|
257
78
|
|
|
258
|
-
|
|
79
|
+
[https://github.com/new-AF/simple-merge-class-names](https://github.com/new-AF/simple-merge-class-names)
|
|
259
80
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
## Conditional Class Inclusion
|
|
263
|
-
|
|
264
|
-
```jsx
|
|
265
|
-
mergeClassNames(condition ? "min-h-dvh" : false);
|
|
266
|
-
|
|
267
|
-
// or if you want preciseness.
|
|
268
|
-
mergeClassNames(condition === true ? "min-h-dvh" : false);
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Avoid Short-circuit Syntax
|
|
272
|
-
|
|
273
|
-
Avoid the syntax (`condition && "class-name"`) because it can produce falsy values (e.g. `0`, `""`, `undefined`, `null`) which will be ignored and warned about.
|
|
274
|
-
|
|
275
|
-
## Return Result
|
|
276
|
-
|
|
277
|
-
String of all merged valid classes. Invalid arguments are ignored and warned about.
|
|
278
|
-
|
|
279
|
-
### Example
|
|
280
|
-
|
|
281
|
-
```jsx
|
|
282
|
-
import { mergeClassNames } from "simple-merge-class-names";
|
|
283
|
-
|
|
284
|
-
// "app min-h-dvh grid grid-rows-[auto_1fr_auto] outline"
|
|
285
|
-
mergeClassNames(
|
|
286
|
-
" app ",
|
|
287
|
-
undefined,
|
|
288
|
-
[" test "],
|
|
289
|
-
{ key: "value" },
|
|
290
|
-
"",
|
|
291
|
-
"min-h-dvh",
|
|
292
|
-
"grid ",
|
|
293
|
-
true,
|
|
294
|
-
null,
|
|
295
|
-
"grid-rows-[auto_1fr_auto]",
|
|
296
|
-
"outline",
|
|
297
|
-
" ",
|
|
298
|
-
);
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## Side Effect
|
|
302
|
-
|
|
303
|
-
`console.warn`s if arguments contain invalid arguments.
|
|
304
|
-
|
|
305
|
-
### Example
|
|
306
|
-
|
|
307
|
-
```
|
|
308
|
-
Ignored invalid argument: >undefined< (undefined)
|
|
309
|
-
Ignored invalid argument: > test < (object)
|
|
310
|
-
Ignored invalid argument: >[object Object]< (object)
|
|
311
|
-
Ignored empty string: ""
|
|
312
|
-
Ignored invalid argument: >true< (boolean)
|
|
313
|
-
Ignored invalid argument: >null< (object)
|
|
314
|
-
Ignored whitespace string:
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
> _It can be empy_
|
|
318
|
-
|
|
319
|
-
1. **Valid `string`, never whitespace, always length >= 1**
|
|
320
|
-
|
|
321
|
-
## Chaining
|
|
322
|
-
|
|
323
|
-
Because of safe return types you can chain calls safely without worrying about warnings or arguments being ignored.
|
|
324
|
-
|
|
325
|
-
_So this is OK:_
|
|
326
|
-
|
|
327
|
-
```js
|
|
328
|
-
mergeClassNames(condition ? "disabled" : mergeClassNames(...) )
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Usage of Browser Debugger
|
|
332
|
-
|
|
333
|
-
1. Use **`import {mergeClassNamesDebugger as mergeClassNames}`** to debug the entire file.
|
|
334
|
-
|
|
335
|
-
```jsx
|
|
336
|
-
import { mergeClassNamesDebugger as mergeClassNames } from "simple-merge-class-names";
|
|
337
|
-
|
|
338
|
-
const Component = ({ condition }) => {
|
|
339
|
-
return (
|
|
340
|
-
<div
|
|
341
|
-
className={mergeClassNames(
|
|
342
|
-
"app",
|
|
343
|
-
condition ? "min-h-dvh" : false,
|
|
344
|
-
"grid",
|
|
345
|
-
"grid-rows-[auto_1fr_auto]",
|
|
346
|
-
"outline",
|
|
347
|
-
)}
|
|
348
|
-
>
|
|
349
|
-
Hello, world!
|
|
350
|
-
</div>
|
|
351
|
-
);
|
|
352
|
-
};
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
2. Enable Debugger
|
|
356
|
-
- _For chromium-based browsers it's On by default and you don't need to do anything AFAIK._
|
|
357
|
-
- _For Firefox:_ Open **_Developer Tools_:**
|
|
358
|
-
- _Make Sure_ **_Debugger_** _(tab)_ -> **`Pause on debugger statement`** is ticked.
|
|
359
|
-
- Keep Dev Tools open.
|
|
360
|
-
|
|
361
|
-

|
|
362
|
-
|
|
363
|
-
3. Refresh the page, the debugger should connect:
|
|
364
|
-
- Navigate to the **_Call stack_**
|
|
365
|
-
- Click the function/component right before _`mergeClassNamesDebugger`_
|
|
366
|
-
|
|
367
|
-

|
|
368
|
-
|
|
369
|
-
4. Hover over the arguments, one or several should be invalid:
|
|
370
|
-
|
|
371
|
-

|
|
372
|
-
|
|
373
|
-
## Testing Source Code
|
|
374
|
-
|
|
375
|
-
This project uses `Vitest` as the test runner for fast and modern testing.
|
|
376
|
-
|
|
377
|
-
### Run Once
|
|
378
|
-
|
|
379
|
-
```bash
|
|
380
|
-
git clone https://github.com/new-AF/simple-merge-class-names
|
|
381
|
-
cd simple-merge-class-names
|
|
382
|
-
pnpm install
|
|
383
|
-
pnpm test
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
### Run Watch Mode
|
|
387
|
-
|
|
388
|
-
```bash
|
|
389
|
-
pnpm test:watch
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
## License
|
|
81
|
+
# License
|
|
393
82
|
|
|
394
83
|
This project is licensed under the AGPL-3.0 License. See `LICENSE.txt` for full details.
|
|
395
84
|
|
|
396
|
-
---
|
|
397
|
-
|
|
398
85
|
Enjoy 😉
|