simple-merge-class-names 7.0.2 → 8.0.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 +255 -197
- package/dist/index.d.mts +39 -0
- package/dist/index.mjs +147 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +19 -13
- package/mergeClassNames.d.ts +0 -7
- package/mergeClassNames.js +0 -175
package/README.md
CHANGED
|
@@ -1,73 +1,84 @@
|
|
|
1
1
|
# simple-merge-class-names
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A class names merger for TypeScript, JavaScript, TSX / JSX (React).
|
|
4
4
|
|
|
5
|
-
For
|
|
5
|
+
> For production purposes there is also [https://www.npmjs.com/package/clsx](https://www.npmjs.com/package/clsx)
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
##
|
|
9
|
+
- [simple-merge-class-names](#simple-merge-class-names)
|
|
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)
|
|
40
|
+
|
|
41
|
+
## Stop Starving Gaza
|
|
42
|
+
|
|
43
|
+
- [Donate Direct Aid to Gazan Families](https://gazafunds.com/)
|
|
44
|
+
|
|
45
|
+
- [Call US Congress and Demand Immediate Opening of ALL Gaza Border Crossings](https://act.uscpr.org/a/letaidin)
|
|
46
|
+
|
|
47
|
+
- [Boycott Brands Supporting Gaza Holocaust](https://www.uplift.ie/bds/)
|
|
48
|
+
|
|
49
|
+
- [Legal Action](https://www.hindrajabfoundation.org/perpetrators)
|
|
50
|
+
|
|
51
|
+
## Install
|
|
42
52
|
|
|
43
53
|
```bash
|
|
44
54
|
pnpm add simple-merge-class-names
|
|
45
|
-
```
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
# or
|
|
48
57
|
yarn add simple-merge-class-names
|
|
49
|
-
```
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
# or
|
|
52
60
|
npm install simple-merge-class-names
|
|
53
61
|
```
|
|
54
62
|
|
|
55
|
-
###
|
|
63
|
+
### Install `Prettier` too
|
|
64
|
+
|
|
65
|
+
[https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
|
56
66
|
|
|
57
|
-
|
|
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).
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
## Exported Functions
|
|
60
70
|
|
|
61
|
-
|
|
71
|
+
| | `console.warn`s | Invokes JS `debugger;` statement on invalid arguments, which pauses execution when Debugger is attached |
|
|
72
|
+
| ------------------------- | --------------- | ------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `mergeClassNames` | ✅ | ❌ |
|
|
74
|
+
| `mergeClassNamesDebugger` | ✅ | ✅ |
|
|
62
75
|
|
|
63
|
-
## Usage
|
|
76
|
+
## Non-scale Usage
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
| ------------------------- | ----------------------- | ------------------ |
|
|
67
|
-
| `mergeClassNames` | ✅ | ❌ |
|
|
68
|
-
| `mergeClassNamesDebugger` | ✅ | ✅ |
|
|
78
|
+
### Example
|
|
69
79
|
|
|
70
80
|
```jsx
|
|
81
|
+
// src/App.jsx
|
|
71
82
|
import { mergeClassNames } from "simple-merge-class-names";
|
|
72
83
|
|
|
73
84
|
const Component = ({ condition }) => {
|
|
@@ -78,7 +89,7 @@ const Component = ({ condition }) => {
|
|
|
78
89
|
condition ? "min-h-dvh" : false,
|
|
79
90
|
"grid",
|
|
80
91
|
"grid-rows-[auto_1fr_auto]",
|
|
81
|
-
"outline"
|
|
92
|
+
"outline",
|
|
82
93
|
)}
|
|
83
94
|
>
|
|
84
95
|
Hello, world!
|
|
@@ -87,32 +98,106 @@ const Component = ({ condition }) => {
|
|
|
87
98
|
};
|
|
88
99
|
```
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
## Scale Usage
|
|
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";
|
|
91
132
|
|
|
92
|
-
|
|
93
|
-
export
|
|
94
|
-
|
|
95
|
-
) => string | false;
|
|
133
|
+
// https://vitejs.dev/config/
|
|
134
|
+
export default defineConfig({
|
|
135
|
+
plugins: [react(), tailwindcss()],
|
|
96
136
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
137
|
+
resolve: {
|
|
138
|
+
alias: {
|
|
139
|
+
"@": path.resolve(__dirname, "src"), // @ now points to "my-react-app/src"
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
});
|
|
100
143
|
```
|
|
101
144
|
|
|
102
|
-
|
|
145
|
+
```js
|
|
146
|
+
// src/mergeClassNames.js
|
|
103
147
|
|
|
104
|
-
|
|
148
|
+
export { mergeClassNames } from "simple-merge-class-names";
|
|
105
149
|
|
|
106
|
-
|
|
150
|
+
// export { mergeClassNames as mergeClassNamesDebugger } from "simple-merge-class-names";
|
|
151
|
+
```
|
|
107
152
|
|
|
108
|
-
|
|
153
|
+
And toggle-comment between the first and second lines as needed.
|
|
109
154
|
|
|
110
|
-
|
|
155
|
+
### Example
|
|
111
156
|
|
|
112
|
-
|
|
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
|
|
190
|
+
|
|
191
|
+
Only 2:
|
|
192
|
+
|
|
193
|
+
1. A valid string (not empty, not fully whitespace)
|
|
194
|
+
2. Value `false`
|
|
195
|
+
|
|
196
|
+
### Example
|
|
113
197
|
|
|
114
198
|
```js
|
|
115
199
|
mergeClassNames(
|
|
200
|
+
condition ? "daisy-btn-active" : false
|
|
116
201
|
"mx-auto",
|
|
117
202
|
"min-dvh ",
|
|
118
203
|
" flex",
|
|
@@ -121,101 +206,119 @@ mergeClassNames(
|
|
|
121
206
|
`
|
|
122
207
|
gap-y-4
|
|
123
208
|
`,
|
|
124
|
-
false,
|
|
125
|
-
condition ? "daisy-btn-active" : false
|
|
126
209
|
);
|
|
127
210
|
```
|
|
128
211
|
|
|
129
|
-
|
|
212
|
+
## Invalid Arguments
|
|
130
213
|
|
|
131
|
-
|
|
214
|
+
Anything that is not a valid argument, this includes:
|
|
132
215
|
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
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`
|
|
226
|
+
- Objects
|
|
227
|
+
- Numbers
|
|
228
|
+
- Big Int
|
|
229
|
+
- Symbols
|
|
146
230
|
|
|
147
|
-
|
|
148
|
-
// Example: These arguments will be **ignored**, and a console.warn will be printed
|
|
231
|
+
_All of above will be **ignored**, and cause a `console.warn` to be printed_
|
|
149
232
|
|
|
233
|
+
### Example
|
|
234
|
+
|
|
235
|
+
```js
|
|
150
236
|
const someVariable = "";
|
|
151
237
|
|
|
152
238
|
mergeClassNames(
|
|
153
|
-
someVariable,
|
|
154
|
-
" ",
|
|
155
|
-
"\n ",
|
|
156
|
-
" \t \n ",
|
|
157
|
-
`
|
|
239
|
+
someVariable,
|
|
240
|
+
" ",
|
|
241
|
+
"\n ",
|
|
242
|
+
" \t \n ",
|
|
243
|
+
`
|
|
158
244
|
\n
|
|
159
245
|
`,
|
|
160
|
-
true,
|
|
161
|
-
undefined,
|
|
162
|
-
null,
|
|
246
|
+
true,
|
|
247
|
+
undefined,
|
|
248
|
+
null,
|
|
163
249
|
{
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
email: "email@example.com",
|
|
250
|
+
name: "name",
|
|
251
|
+
email: "name@example.com",
|
|
167
252
|
},
|
|
168
|
-
123,
|
|
169
|
-
123.45
|
|
253
|
+
123,
|
|
254
|
+
123.45,
|
|
170
255
|
);
|
|
171
256
|
```
|
|
172
257
|
|
|
258
|
+
#### Developer Console Warnings
|
|
259
|
+
|
|
173
260
|

|
|
174
261
|
|
|
175
|
-
|
|
262
|
+
## Conditional Class Inclusion
|
|
263
|
+
|
|
264
|
+
```jsx
|
|
265
|
+
mergeClassNames(condition ? "min-h-dvh" : false);
|
|
176
266
|
|
|
177
|
-
|
|
267
|
+
// or if you want preciseness.
|
|
268
|
+
mergeClassNames(condition === true ? "min-h-dvh" : false);
|
|
269
|
+
```
|
|
178
270
|
|
|
179
|
-
###
|
|
271
|
+
### Avoid Short-circuit Syntax
|
|
180
272
|
|
|
181
|
-
|
|
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.
|
|
182
274
|
|
|
183
|
-
|
|
184
|
-
- _or_ `condition === true ? "class-name" : false` if you want to be specific.
|
|
275
|
+
## Return Result
|
|
185
276
|
|
|
186
|
-
|
|
277
|
+
String of all merged valid classes. Invalid arguments are ignored and warned about.
|
|
187
278
|
|
|
188
|
-
|
|
279
|
+
### Example
|
|
189
280
|
|
|
190
281
|
```jsx
|
|
191
282
|
import { mergeClassNames } from "simple-merge-class-names";
|
|
192
283
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
+
);
|
|
208
299
|
```
|
|
209
300
|
|
|
210
|
-
|
|
301
|
+
## Side Effect
|
|
211
302
|
|
|
212
|
-
|
|
303
|
+
`console.warn`s if arguments contain invalid arguments.
|
|
213
304
|
|
|
214
|
-
|
|
305
|
+
### Example
|
|
215
306
|
|
|
216
|
-
|
|
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**
|
|
217
320
|
|
|
218
|
-
|
|
321
|
+
## Chaining
|
|
219
322
|
|
|
220
323
|
Because of safe return types you can chain calls safely without worrying about warnings or arguments being ignored.
|
|
221
324
|
|
|
@@ -227,90 +330,45 @@ mergeClassNames(condition ? "disabled" : mergeClassNames(...) )
|
|
|
227
330
|
|
|
228
331
|
## Usage of Browser Debugger
|
|
229
332
|
|
|
230
|
-
|
|
333
|
+
1. Use **`import {mergeClassNamesDebugger as mergeClassNames}`** to debug the entire file.
|
|
231
334
|
|
|
232
|
-
|
|
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
|
|
233
356
|
- _For chromium-based browsers it's On by default and you don't need to do anything AFAIK._
|
|
234
357
|
- _For Firefox:_ Open **_Developer Tools_:**
|
|
235
358
|
- _Make Sure_ **_Debugger_** _(tab)_ -> **`Pause on debugger statement`** is ticked.
|
|
236
359
|
- Keep Dev Tools open.
|
|
237
|
-

|
|
238
|
-
|
|
239
|
-
- Use **`import {mergeClassNamesDebugger as mergeClassNames}`** to debug the entire file, and keep the rest intact.
|
|
240
|
-
|
|
241
|
-
```jsx
|
|
242
|
-
import { mergeClassNamesDebugger as mergeClassNames } from "simple-merge-class-names";
|
|
243
|
-
|
|
244
|
-
const Component = ({ condition }) => {
|
|
245
|
-
return (
|
|
246
|
-
<div
|
|
247
|
-
className={mergeClassNames(
|
|
248
|
-
"app",
|
|
249
|
-
condition ? "min-h-dvh" : false,
|
|
250
|
-
"grid",
|
|
251
|
-
"grid-rows-[auto_1fr_auto]",
|
|
252
|
-
"outline"
|
|
253
|
-
)}
|
|
254
|
-
>
|
|
255
|
-
Hello, world!
|
|
256
|
-
</div>
|
|
257
|
-
);
|
|
258
|
-
};
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
- or call `mergeClassNamesDebugger` directly.
|
|
262
|
-
|
|
263
|
-
```jsx
|
|
264
|
-
import { mergeClassNamesDebugger } from "simple-merge-class-names";
|
|
265
|
-
|
|
266
|
-
const Component = ({ condition }) => {
|
|
267
|
-
return (
|
|
268
|
-
<div
|
|
269
|
-
className={mergeClassNamesDebugger(
|
|
270
|
-
"app",
|
|
271
|
-
condition ? "min-h-dvh" : false,
|
|
272
|
-
"grid",
|
|
273
|
-
"grid-rows-[auto_1fr_auto]",
|
|
274
|
-
"outline"
|
|
275
|
-
)}
|
|
276
|
-
>
|
|
277
|
-
Hello, world!
|
|
278
|
-
</div>
|
|
279
|
-
);
|
|
280
|
-
};
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
- Refresh the page, the debugger should connect:
|
|
284
|
-
|
|
285
|
-
- Navigate to the **_Call stack_**
|
|
286
|
-
- Click the function/component right before _`mergeClassNamesDebugger`_
|
|
287
|
-
|
|
288
|
-

|
|
289
|
-
|
|
290
|
-
- Hover over the arguments, one or several should be invalid:
|
|
291
|
-

|
|
292
|
-
|
|
293
|
-
## VSCode Workflow To Minimize Typing Strain
|
|
294
|
-
|
|
295
|
-
Use single quotes around class names, and activate `Prettier` which will neatly format and arrange the classes.
|
|
296
|
-
|
|
297
|
-
- Install `Prettier`
|
|
298
|
-
- Enable `Editor: Word Wrap`:
|
|
299
|
-
|
|
300
|
-
- Open `Settings (UI)` → `Editor: Word Wrap` → `on`
|
|
301
|
-
- _or_ `User Settings (JSON)` and add this entry `"editor.wordWrap": "on"`
|
|
302
360
|
|
|
303
|
-
|
|
304
|
-
- Save the file
|
|
361
|
+

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

|
|
367
|
+

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

|
|
314
372
|
|
|
315
373
|
## Testing Source Code
|
|
316
374
|
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type ValidArgument = string | false;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* mergeClassNames - A class names merger for TypeScript, JavaScript, TSX / JSX (React).
|
|
5
|
+
*
|
|
6
|
+
* @license AGPL-3.0
|
|
7
|
+
* Copyright (C) 2026 Abdullah Fatota
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
* This program is free software: you can redistribute it and/or modify
|
|
11
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
12
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
13
|
+
* (at your option) any later version.
|
|
14
|
+
*
|
|
15
|
+
* This program is distributed in the hope that it will be useful,
|
|
16
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18
|
+
* GNU Affero General Public License for more details.
|
|
19
|
+
*
|
|
20
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
21
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Valid arguments:
|
|
25
|
+
1) valid strings, which are non-empty strings, and non-whitespace strings
|
|
26
|
+
2) value `false`
|
|
27
|
+
|
|
28
|
+
Invalid arguments: anything else e.g.
|
|
29
|
+
- empty strings
|
|
30
|
+
- whitespace strings
|
|
31
|
+
- numbers
|
|
32
|
+
- value true
|
|
33
|
+
-
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
declare const mergeClassNames: (...input: ValidArgument[]) => string;
|
|
37
|
+
declare const mergeClassNamesDebugger: (...input: ValidArgument[]) => string;
|
|
38
|
+
|
|
39
|
+
export { mergeClassNames, mergeClassNamesDebugger };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
var classify = (value) => {
|
|
3
|
+
if (value === false) {
|
|
4
|
+
return {
|
|
5
|
+
status: "ignore",
|
|
6
|
+
value
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (typeof value !== "string") {
|
|
10
|
+
return {
|
|
11
|
+
status: "invalid",
|
|
12
|
+
value,
|
|
13
|
+
reason: 0 /* NotAString */
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (value === "") {
|
|
17
|
+
return {
|
|
18
|
+
status: "invalid",
|
|
19
|
+
value,
|
|
20
|
+
reason: 1 /* EmptyString */
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const trimmed = value.trim();
|
|
24
|
+
if (trimmed === "") {
|
|
25
|
+
return {
|
|
26
|
+
status: "invalid",
|
|
27
|
+
value,
|
|
28
|
+
reason: 2 /* Whitespace */
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
status: "class-name",
|
|
33
|
+
value: trimmed
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
var getClassNames = (values) => {
|
|
37
|
+
return values.filter((obj) => obj.status === "class-name");
|
|
38
|
+
};
|
|
39
|
+
var getInvalid = (values) => {
|
|
40
|
+
return values.filter((obj) => obj.status === "invalid");
|
|
41
|
+
};
|
|
42
|
+
var warningMessage = ({
|
|
43
|
+
value,
|
|
44
|
+
reason
|
|
45
|
+
}) => {
|
|
46
|
+
if (reason === 0 /* NotAString */) {
|
|
47
|
+
if (value === null || value === void 0) {
|
|
48
|
+
return `Ignored non-string argument: ${value}`;
|
|
49
|
+
}
|
|
50
|
+
if (value === true) {
|
|
51
|
+
return `Ignored non-string argument: ${value} (boolean)`;
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
const sub = value.slice(0, 3);
|
|
55
|
+
const string = JSON.stringify(sub).slice(1, -1);
|
|
56
|
+
const ellipsisPart = value.length > sub.length ? ", ..." : "";
|
|
57
|
+
return `Ignored non-string argument: array ([${string}${ellipsisPart}])`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (reason === 1 /* EmptyString */) {
|
|
61
|
+
return `Ignored empty string argument.`;
|
|
62
|
+
}
|
|
63
|
+
if (reason === 2 /* Whitespace */) {
|
|
64
|
+
return `Ignored whitespace string argument: "${value}"`;
|
|
65
|
+
}
|
|
66
|
+
return `Ignored non-string argument: ${value} (${typeof value})`;
|
|
67
|
+
};
|
|
68
|
+
var warn = (invalid) => {
|
|
69
|
+
const warning = warningMessage(invalid);
|
|
70
|
+
console.warn(warning);
|
|
71
|
+
};
|
|
72
|
+
var activateDebugger = (_invalid) => {
|
|
73
|
+
debugger;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/mergeClassNames.ts
|
|
77
|
+
var mergeClassNamesCore = (values, onClassifiedInvalid) => {
|
|
78
|
+
const classified = values.map(classify);
|
|
79
|
+
if (onClassifiedInvalid) {
|
|
80
|
+
getInvalid(classified).forEach(onClassifiedInvalid);
|
|
81
|
+
}
|
|
82
|
+
const classNames = getClassNames(classified).map(
|
|
83
|
+
({ value }) => value
|
|
84
|
+
);
|
|
85
|
+
const finalClassName = classNames.join(" ");
|
|
86
|
+
return finalClassName;
|
|
87
|
+
};
|
|
88
|
+
var createCustomMergeClassNames = (options) => {
|
|
89
|
+
const invalidHandlers = [];
|
|
90
|
+
if (options["console-warn-invalid-and-whitespace-arguments"]) {
|
|
91
|
+
invalidHandlers.push(warn);
|
|
92
|
+
}
|
|
93
|
+
if (options["activate-debugger-on-invalid-arguments"]) {
|
|
94
|
+
invalidHandlers.push(activateDebugger);
|
|
95
|
+
}
|
|
96
|
+
const combinedInvalidHandler = (value) => {
|
|
97
|
+
invalidHandlers.forEach((func) => func(value));
|
|
98
|
+
};
|
|
99
|
+
return (...input) => mergeClassNamesCore(
|
|
100
|
+
input,
|
|
101
|
+
invalidHandlers.length > 0 ? combinedInvalidHandler : void 0
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
var mergeClassNames = createCustomMergeClassNames({
|
|
105
|
+
"console-warn-invalid-and-whitespace-arguments": true,
|
|
106
|
+
"activate-debugger-on-invalid-arguments": false
|
|
107
|
+
});
|
|
108
|
+
var mergeClassNamesDebugger = createCustomMergeClassNames({
|
|
109
|
+
"console-warn-invalid-and-whitespace-arguments": true,
|
|
110
|
+
"activate-debugger-on-invalid-arguments": true
|
|
111
|
+
});
|
|
112
|
+
/**
|
|
113
|
+
* mergeClassNames - A class names merger for TypeScript, JavaScript, TSX / JSX (React).
|
|
114
|
+
*
|
|
115
|
+
* @license AGPL-3.0
|
|
116
|
+
* Copyright (C) 2026 Abdullah Fatota
|
|
117
|
+
*
|
|
118
|
+
*
|
|
119
|
+
* This program is free software: you can redistribute it and/or modify
|
|
120
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
121
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
122
|
+
* (at your option) any later version.
|
|
123
|
+
*
|
|
124
|
+
* This program is distributed in the hope that it will be useful,
|
|
125
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
126
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
127
|
+
* GNU Affero General Public License for more details.
|
|
128
|
+
*
|
|
129
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
130
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
Valid arguments:
|
|
134
|
+
1) valid strings, which are non-empty strings, and non-whitespace strings
|
|
135
|
+
2) value `false`
|
|
136
|
+
|
|
137
|
+
Invalid arguments: anything else e.g.
|
|
138
|
+
- empty strings
|
|
139
|
+
- whitespace strings
|
|
140
|
+
- numbers
|
|
141
|
+
- value true
|
|
142
|
+
-
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
export { mergeClassNames, mergeClassNamesDebugger };
|
|
146
|
+
//# sourceMappingURL=index.mjs.map
|
|
147
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/mergeClassNames.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import {\r\n ValidArgument,\r\n Classified,\r\n ClassifiedInvalid,\r\n ClassifiedInvalidReason,\r\n ClassifiedClassName,\r\n} from \"./types\";\r\n\r\n// classifies input arguments\r\nexport const classify = (value: ValidArgument): Classified => {\r\n // FP pattern of mapping values with extra information.\r\n // The core computes data.\r\n // because TS types disappear in JS runtime\r\n\r\n // valid but ignored\r\n if (value === false) {\r\n return {\r\n status: \"ignore\",\r\n value,\r\n };\r\n }\r\n\r\n // invalid\r\n if (typeof value !== \"string\") {\r\n return {\r\n status: \"invalid\",\r\n value,\r\n reason: ClassifiedInvalidReason.NotAString,\r\n };\r\n }\r\n\r\n // it's a string\r\n\r\n // invalid.\r\n if (value === \"\") {\r\n return {\r\n status: \"invalid\",\r\n value,\r\n reason: ClassifiedInvalidReason.EmptyString,\r\n };\r\n }\r\n\r\n const trimmed = value.trim();\r\n\r\n // invalid\r\n if (trimmed === \"\") {\r\n return {\r\n status: \"invalid\",\r\n value,\r\n reason: ClassifiedInvalidReason.Whitespace,\r\n };\r\n }\r\n\r\n // valid\r\n return {\r\n status: \"class-name\",\r\n value: trimmed,\r\n };\r\n};\r\n\r\n// get only valid objects\r\nexport const getClassNames = (values: Classified[]): ClassifiedClassName[] => {\r\n return values.filter((obj) => obj.status === \"class-name\");\r\n};\r\n\r\n// get only valid objects\r\nexport const getInvalid = (values: Classified[]): ClassifiedInvalid[] => {\r\n return values.filter((obj) => obj.status === \"invalid\");\r\n};\r\n\r\nexport const warningMessage = ({\r\n value,\r\n reason,\r\n}: ClassifiedInvalid): string => {\r\n if (reason === ClassifiedInvalidReason.NotAString) {\r\n // null, undefined\r\n if (value === null || value === undefined) {\r\n return `Ignored non-string argument: ${value}`;\r\n }\r\n\r\n // true (because false was filtered out)\r\n if (value === true) {\r\n return `Ignored non-string argument: ${value} (boolean)`;\r\n }\r\n\r\n // array\r\n if (Array.isArray(value)) {\r\n const sub = value.slice(0, 3);\r\n const string = JSON.stringify(sub).slice(1, -1);\r\n const ellipsisPart = value.length > sub.length ? \", ...\" : \"\";\r\n\r\n return `Ignored non-string argument: array ([${string}${ellipsisPart}])`;\r\n }\r\n }\r\n\r\n // empty string\r\n if (reason === ClassifiedInvalidReason.EmptyString) {\r\n return `Ignored empty string argument.`;\r\n }\r\n\r\n // whitespace\r\n if (reason === ClassifiedInvalidReason.Whitespace) {\r\n return `Ignored whitespace string argument: \"${value}\"`;\r\n }\r\n\r\n // object, symbol, etc.\r\n return `Ignored non-string argument: ${value} (${typeof value})`;\r\n};\r\n\r\n// console.warn\r\nexport const warn = (invalid: ClassifiedInvalid) => {\r\n const warning = warningMessage(invalid);\r\n\r\n console.warn(warning);\r\n};\r\n\r\n// activates debugger\r\nexport const activateDebugger = (_invalid: ClassifiedInvalid) => {\r\n debugger;\r\n};\r\n","/**\r\n * mergeClassNames - A class names merger for TypeScript, JavaScript, TSX / JSX (React).\r\n *\r\n * @license AGPL-3.0\r\n * Copyright (C) 2026 Abdullah Fatota\r\n *\r\n *\r\n * This program is free software: you can redistribute it and/or modify\r\n * it under the terms of the GNU Affero General Public License as published by\r\n * the Free Software Foundation, either version 3 of the License, or\r\n * (at your option) any later version.\r\n *\r\n * This program is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r\n * GNU Affero General Public License for more details.\r\n *\r\n * You should have received a copy of the GNU Affero General Public License\r\n * along with this program. If not, see <https://www.gnu.org/licenses/>.\r\n \r\n\r\nValid arguments:\r\n 1) valid strings, which are non-empty strings, and non-whitespace strings\r\n 2) value `false`\r\n\r\nInvalid arguments: anything else e.g.\r\n - empty strings\r\n - whitespace strings\r\n - numbers\r\n - value true\r\n - \r\n*/\r\n\r\nimport {\r\n ValidArgument,\r\n ClassifiedInvalidFunction,\r\n ClassifiedInvalid,\r\n CustomOptions,\r\n} from \"./types\";\r\n\r\nimport {\r\n classify,\r\n getInvalid,\r\n warn,\r\n activateDebugger,\r\n getClassNames,\r\n} from \"./utils\";\r\n\r\n// joins valid strings into final className\r\nconst mergeClassNamesCore = (\r\n values: ValidArgument[],\r\n onClassifiedInvalid?: ClassifiedInvalidFunction,\r\n) => {\r\n // classify arguments\r\n const classified = values.map(classify);\r\n\r\n // optional call invalid arguments handlers: warn and/or activate debugger\r\n if (onClassifiedInvalid) {\r\n getInvalid(classified).forEach(onClassifiedInvalid);\r\n }\r\n\r\n // valid strings only\r\n const classNames: string[] = getClassNames(classified).map(\r\n ({ value }) => value,\r\n );\r\n\r\n const finalClassName = classNames.join(\" \");\r\n return finalClassName;\r\n};\r\n\r\n// creates custom mergeClassNames e.g. warn = false, activate debugger = true\r\nexport const createCustomMergeClassNames = (options: CustomOptions) => {\r\n const invalidHandlers: ClassifiedInvalidFunction[] = [];\r\n\r\n if (options[\"console-warn-invalid-and-whitespace-arguments\"]) {\r\n invalidHandlers.push(warn);\r\n }\r\n\r\n if (options[\"activate-debugger-on-invalid-arguments\"]) {\r\n invalidHandlers.push(activateDebugger);\r\n }\r\n\r\n const combinedInvalidHandler = (value: ClassifiedInvalid) => {\r\n invalidHandlers.forEach((func) => func(value));\r\n };\r\n\r\n // construct the mergeClassNames function\r\n return (...input: ValidArgument[]) =>\r\n mergeClassNamesCore(\r\n input,\r\n invalidHandlers.length > 0 ? combinedInvalidHandler : undefined,\r\n );\r\n};\r\n\r\nexport const mergeClassNames = createCustomMergeClassNames({\r\n \"console-warn-invalid-and-whitespace-arguments\": true,\r\n \"activate-debugger-on-invalid-arguments\": false,\r\n});\r\n\r\nexport const mergeClassNamesDebugger = createCustomMergeClassNames({\r\n \"console-warn-invalid-and-whitespace-arguments\": true,\r\n \"activate-debugger-on-invalid-arguments\": true,\r\n});\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simple-merge-class-names",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": " A class names merger for TypeScript, JavaScript, TSX, and JSX (React)",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"import": "./
|
|
8
|
-
"types": "./
|
|
7
|
+
"import": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.mts"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
+
"main": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
11
13
|
"files": [
|
|
12
|
-
"
|
|
13
|
-
"mergeClassNames.d.ts",
|
|
14
|
+
"dist",
|
|
14
15
|
"LICENSE.txt",
|
|
15
16
|
"README.md"
|
|
16
17
|
],
|
|
17
18
|
"sideEffects": false,
|
|
18
19
|
"keywords": [
|
|
19
|
-
"mergeClassNames",
|
|
20
|
-
"merge",
|
|
21
20
|
"class-names-merger",
|
|
22
|
-
"
|
|
21
|
+
"classes-merger",
|
|
22
|
+
"jsx",
|
|
23
|
+
"merge",
|
|
24
|
+
"mergeClassNames",
|
|
25
|
+
"mergeClassNamesDebugger",
|
|
26
|
+
"merger",
|
|
23
27
|
"react",
|
|
24
|
-
"tailwindcss"
|
|
28
|
+
"tailwindcss",
|
|
29
|
+
"tsx",
|
|
30
|
+
"utility"
|
|
25
31
|
],
|
|
26
32
|
"author": "Abdullah Fatota",
|
|
27
33
|
"license": "AGPL-3.0",
|
|
@@ -29,14 +35,14 @@
|
|
|
29
35
|
"type": "git",
|
|
30
36
|
"url": "git+https://github.com/new-AF/simple-merge-class-names.git"
|
|
31
37
|
},
|
|
32
|
-
"bugs": {
|
|
33
|
-
"url": "https://github.com/new-AF/simple-merge-class-names/issues"
|
|
34
|
-
},
|
|
35
38
|
"homepage": "https://github.com/new-AF/simple-merge-class-names",
|
|
36
39
|
"devDependencies": {
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"typescript": "^6.0.3",
|
|
37
42
|
"vitest": "^3.2.3"
|
|
38
43
|
},
|
|
39
44
|
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
40
46
|
"test": "vitest",
|
|
41
47
|
"test:watch": "vitest --watch",
|
|
42
48
|
"test:ui": "vitest --ui"
|
package/mergeClassNames.d.ts
DELETED
package/mergeClassNames.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mergeClassNames - A straightforward utility for merging CSS class names in React + Tailwind, and other JavaScript projects.
|
|
3
|
-
*
|
|
4
|
-
* @license AGPL-3.0
|
|
5
|
-
* Copyright (C) 2025 Abdullah Fatota
|
|
6
|
-
*
|
|
7
|
-
* Example usage:
|
|
8
|
-
* import { mergeClassNames } from "simple-merge-class-names";
|
|
9
|
-
*
|
|
10
|
-
* function MyComponent() {
|
|
11
|
-
* return (
|
|
12
|
-
* <div
|
|
13
|
-
* className={mergeClassNames(
|
|
14
|
-
* "app",
|
|
15
|
-
* "min-h-dvh",
|
|
16
|
-
* "grid",
|
|
17
|
-
* "grid-rows-[auto_1fr_auto]",
|
|
18
|
-
* "outline"
|
|
19
|
-
* )}
|
|
20
|
-
* >
|
|
21
|
-
* Hello, world!
|
|
22
|
-
* </div>
|
|
23
|
-
* );
|
|
24
|
-
* }
|
|
25
|
-
*
|
|
26
|
-
* This program is free software: you can redistribute it and/or modify
|
|
27
|
-
* it under the terms of the GNU Affero General Public License as published by
|
|
28
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
29
|
-
* (at your option) any later version.
|
|
30
|
-
*
|
|
31
|
-
* This program is distributed in the hope that it will be useful,
|
|
32
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
33
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
34
|
-
* GNU Affero General Public License for more details.
|
|
35
|
-
*
|
|
36
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
37
|
-
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
const partition = (array, keepPredicate) => {
|
|
41
|
-
const keep = [];
|
|
42
|
-
const ignore = [];
|
|
43
|
-
for (const element of array) {
|
|
44
|
-
const arrayRef = keepPredicate(element) ? keep : ignore;
|
|
45
|
-
arrayRef.push(element);
|
|
46
|
-
}
|
|
47
|
-
return [keep, ignore];
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const filterArguments = (argumentsArray) => {
|
|
51
|
-
/*
|
|
52
|
-
returns {
|
|
53
|
-
valid: bool,
|
|
54
|
-
value: any
|
|
55
|
-
(optional) isString: bool,
|
|
56
|
-
(optional) valueType: any
|
|
57
|
-
(optional) isValueFalse
|
|
58
|
-
(optional) isValidString: bool
|
|
59
|
-
}
|
|
60
|
-
*/
|
|
61
|
-
const isValidArgument = (value) => {
|
|
62
|
-
const valueType = typeof value;
|
|
63
|
-
|
|
64
|
-
if (value === false) {
|
|
65
|
-
return { valid: true, value };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (valueType === "string") {
|
|
69
|
-
const trimmed = value.trim();
|
|
70
|
-
|
|
71
|
-
// invalid string
|
|
72
|
-
if (trimmed === "") {
|
|
73
|
-
return {
|
|
74
|
-
valid: false,
|
|
75
|
-
value,
|
|
76
|
-
isString: true,
|
|
77
|
-
isValidString: false,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// valid string
|
|
81
|
-
return {
|
|
82
|
-
valid: true,
|
|
83
|
-
value: trimmed,
|
|
84
|
-
isString: true,
|
|
85
|
-
isValidString: true,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// everything else
|
|
90
|
-
return { valid: false, value, isString: false, valueType };
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// array of objects
|
|
94
|
-
const newArguments = argumentsArray.map((element) =>
|
|
95
|
-
isValidArgument(element)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// includes `false`
|
|
99
|
-
const [validArgumentsWithFalse, invalidArguments] = partition(
|
|
100
|
-
newArguments,
|
|
101
|
-
({ valid }) => valid === true
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// ignore `false`
|
|
105
|
-
const [validArguments, _] = partition(
|
|
106
|
-
validArgumentsWithFalse,
|
|
107
|
-
({ value }) => value !== false
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// console.log({ validArgumentsWithFalse, validArguments, invalidArguments });
|
|
111
|
-
|
|
112
|
-
return { validArguments, invalidArguments };
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const warnMessage = (
|
|
116
|
-
{ value, isString, valueType, isValidString },
|
|
117
|
-
callerFunctionName
|
|
118
|
-
) => {
|
|
119
|
-
if (isString === false) {
|
|
120
|
-
return `[${callerFunctionName}] Ignored non-string >${value}< (${valueType})`;
|
|
121
|
-
} else if (isValidString === false) {
|
|
122
|
-
return `[${callerFunctionName}] Ignored empty string "${value}"`;
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const warnOnly = (
|
|
127
|
-
invalidArgumentsArray,
|
|
128
|
-
callerFunctionName,
|
|
129
|
-
debuggerVariantName
|
|
130
|
-
) =>
|
|
131
|
-
invalidArgumentsArray.forEach((obj) => {
|
|
132
|
-
const message = warnMessage(obj, callerFunctionName);
|
|
133
|
-
console.warn(`${message}`);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const warnDebug = (invalidArgumentsArray, callerFunctionName) =>
|
|
137
|
-
invalidArgumentsArray.forEach((obj) => {
|
|
138
|
-
console.warn(warnMessage(obj, callerFunctionName));
|
|
139
|
-
debugger;
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const join = (argumentsArray) => {
|
|
143
|
-
const space = "\x20"; // ASCII for single space (" "), decimal 32
|
|
144
|
-
const classNames = argumentsArray.map(({ value }) => value).join(space);
|
|
145
|
-
return classNames;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const finalResult = (joinedClassNames) =>
|
|
149
|
-
joinedClassNames === "" ? false : joinedClassNames;
|
|
150
|
-
|
|
151
|
-
// exported
|
|
152
|
-
// export const mergeClassNamesNoWarning = (...argumentsArray) => {
|
|
153
|
-
// const { validArguments, _ } = filterArguments(argumentsArray);
|
|
154
|
-
// const classNames = join(validArguments);
|
|
155
|
-
// const result = finalResult(classNames);
|
|
156
|
-
// return result;
|
|
157
|
-
// };
|
|
158
|
-
|
|
159
|
-
export const mergeClassNames = (...argumentsArray) => {
|
|
160
|
-
const { validArguments, invalidArguments } =
|
|
161
|
-
filterArguments(argumentsArray);
|
|
162
|
-
warnOnly(invalidArguments, "mergeClassNames", "mergeClassNamesDebugger");
|
|
163
|
-
const classNames = join(validArguments);
|
|
164
|
-
const result = finalResult(classNames);
|
|
165
|
-
return result;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
export const mergeClassNamesDebugger = (...argumentsArray) => {
|
|
169
|
-
const { validArguments, invalidArguments } =
|
|
170
|
-
filterArguments(argumentsArray);
|
|
171
|
-
warnDebug(invalidArguments, "mergeClassNamesDebugger");
|
|
172
|
-
const classNames = join(validArguments);
|
|
173
|
-
const result = finalResult(classNames);
|
|
174
|
-
return result;
|
|
175
|
-
};
|