uiconfig-blueprint 0.1.0-dev.11 → 0.1.0-dev.12
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/dist/{allPaths-Dhco1c7a.js → allPaths-DtaFoocb.js} +5 -5
- package/dist/{allPaths-Dhco1c7a.js.map → allPaths-DtaFoocb.js.map} +1 -1
- package/dist/{allPathsLoader-BNvrKJa2.js → allPathsLoader-B5mUU0us.js} +4 -4
- package/dist/{allPathsLoader-BNvrKJa2.js.map → allPathsLoader-B5mUU0us.js.map} +1 -1
- package/dist/components/NumericInput.d.ts +0 -3
- package/dist/{index-GANXo7JZ.js → index-BPcAfGYu.js} +1992 -1969
- package/dist/index-BPcAfGYu.js.map +1 -0
- package/dist/{index-BvGAMcRo.js → index-BsXaCp6n.js} +2 -2
- package/dist/{index-BvGAMcRo.js.map → index-BsXaCp6n.js.map} +1 -1
- package/dist/{index-B1k4Miq7.js → index-CIFbDQFr.js} +2 -2
- package/dist/{index-B1k4Miq7.js.map → index-CIFbDQFr.js.map} +1 -1
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{splitPathsBySizeLoader-DGIXBgyZ.js → splitPathsBySizeLoader-BGjtD8Dg.js} +5 -5
- package/dist/{splitPathsBySizeLoader-DGIXBgyZ.js.map → splitPathsBySizeLoader-BGjtD8Dg.js.map} +1 -1
- package/dist/utils.d.ts +1 -0
- package/docs/classes/UI.html +3 -3
- package/docs/classes/UiConfigRendererBlueprint.html +3 -3
- package/lib/css/renderer.css +11 -5
- package/lib/css/renderer.css.map +1 -1
- package/lib/esm/bpComponents/BPButtonComponent.js +1 -1
- package/lib/esm/bpComponents/BPButtonComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPColorInputComponent.js +1 -1
- package/lib/esm/bpComponents/BPColorInputComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPDropdownInputComponent.js +3 -2
- package/lib/esm/bpComponents/BPDropdownInputComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPFolderComponent.js +1 -1
- package/lib/esm/bpComponents/BPFolderComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPLabelledComponent.js +2 -1
- package/lib/esm/bpComponents/BPLabelledComponent.js.map +1 -1
- package/lib/esm/components/ExtendedNumericInput.js +1 -1
- package/lib/esm/components/NumericInput.d.ts +0 -3
- package/lib/esm/components/NumericInput.js +7 -17
- package/lib/esm/components/NumericInput.js.map +1 -1
- package/lib/esm/renderer.css.js +1 -1
- package/lib/esm/utils.d.ts +1 -0
- package/lib/esm/utils.js +19 -0
- package/lib/esm/utils.js.map +1 -0
- package/package.json +11 -4
- package/src/bpComponents/BPButtonComponent.tsx +1 -1
- package/src/bpComponents/BPColorInputComponent.tsx +1 -1
- package/src/bpComponents/BPDropdownInputComponent.tsx +3 -2
- package/src/bpComponents/BPFolderComponent.scss +17 -1
- package/src/bpComponents/BPFolderComponent.tsx +4 -2
- package/src/bpComponents/BPLabelledComponent.tsx +2 -2
- package/src/components/ExtendedNumericInput.tsx +1 -1
- package/src/components/NumericInput.tsx +17 -17
- package/src/renderer.scss +4 -1
- package/src/utils.ts +34 -0
- package/dist/index-GANXo7JZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cleanLabel(varName?: string): string | undefined;
|
package/lib/esm/utils.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function cleanLabel(varName) {
|
|
2
|
+
if (!varName || typeof varName !== 'string') {
|
|
3
|
+
return varName;
|
|
4
|
+
}
|
|
5
|
+
let result = varName.trim();
|
|
6
|
+
if (!result)
|
|
7
|
+
return '';
|
|
8
|
+
if (result.includes(' '))
|
|
9
|
+
return result;
|
|
10
|
+
result = result.replace(/_/g, ' ');
|
|
11
|
+
result = result.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2');
|
|
12
|
+
result = result.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
13
|
+
result = result.replace(/([a-zA-Z])(\d)/g, '$1 $2');
|
|
14
|
+
result = result.replace(/(\d)([a-zA-Z])/g, '$1 $2');
|
|
15
|
+
const words = result.split(/\s+/).filter(word => word.length > 0);
|
|
16
|
+
const capitalizedWords = words.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
17
|
+
return capitalizedWords.join(' ');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,OAAgB;IACvC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,IAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAEvC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAInC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;IAEzD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAGpD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAGpD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAGpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClE,MAAM,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACtC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAC7D,CAAC;IAGF,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uiconfig-blueprint",
|
|
3
3
|
"name:umd": "bpui",
|
|
4
|
-
"version": "0.1.0-dev.
|
|
4
|
+
"version": "0.1.0-dev.12",
|
|
5
5
|
"description": "Blueprint.js wrapper and custom components for web controls UI. To be used with uiconfig.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
"require": "./dist/index.js",
|
|
17
17
|
"browser": "./dist/index.js"
|
|
18
18
|
},
|
|
19
|
+
"./dist/": {
|
|
20
|
+
"import": "./dist/",
|
|
21
|
+
"require": "./dist/"
|
|
22
|
+
},
|
|
19
23
|
"./lib/esm": {
|
|
20
|
-
"types": "./
|
|
21
|
-
"import": "./lib/esm/index.js"
|
|
22
|
-
"require": "./dist/index.js"
|
|
24
|
+
"types": "./lib/esm/index.d.ts",
|
|
25
|
+
"import": "./lib/esm/index.js"
|
|
23
26
|
},
|
|
24
27
|
"./lib/esm/*": {
|
|
25
28
|
"types": "./lib/esm/*.d.ts",
|
|
@@ -29,6 +32,10 @@
|
|
|
29
32
|
"import": "./lib/css/*.css",
|
|
30
33
|
"require": "./lib/css/*.css"
|
|
31
34
|
},
|
|
35
|
+
"./src/": {
|
|
36
|
+
"import": "./src/",
|
|
37
|
+
"require": "./src/"
|
|
38
|
+
},
|
|
32
39
|
"./package.json": "./package.json"
|
|
33
40
|
},
|
|
34
41
|
"files": [
|
|
@@ -22,7 +22,7 @@ export class BPButtonComponent extends BPLabelledComponent<()=>void, BPLabelledC
|
|
|
22
22
|
style={{flexBasis: this.state.baseWidth ?? this.flexBasis}}
|
|
23
23
|
>
|
|
24
24
|
<Button className="bpButton"
|
|
25
|
-
disabled={this.state.disabled}
|
|
25
|
+
disabled={this.state.disabled || this.state.readOnly}
|
|
26
26
|
intent={Intent.PRIMARY}
|
|
27
27
|
// small={true}
|
|
28
28
|
fill={true}
|
|
@@ -39,7 +39,7 @@ export class BPColorInputComponent extends BPValueComponent<ColorRepresentation,
|
|
|
39
39
|
else console.error('not supported color', val)
|
|
40
40
|
this._tempColor.set(val)
|
|
41
41
|
if (srgbConvert) this._tempColor.convertLinearToSRGB()
|
|
42
|
-
const value = '#' + this._tempColor.getHexString()
|
|
42
|
+
const value = '#' + this._tempColor.getHexString().toUpperCase()
|
|
43
43
|
// console.log('color', mode, value, val)
|
|
44
44
|
return {...state, mode, value, lastValue: val, srgbConvert} // default config.srgb = false
|
|
45
45
|
}
|
|
@@ -3,6 +3,7 @@ import {Button, MenuItem} from "@blueprintjs/core";
|
|
|
3
3
|
import {BPInputComponent} from "./BPInputComponent";
|
|
4
4
|
import {BPValueComponentState} from "./BPValueComponent";
|
|
5
5
|
import {ItemRenderer, Select} from "@blueprintjs/select";
|
|
6
|
+
import {cleanLabel} from "../utils";
|
|
6
7
|
|
|
7
8
|
export interface DropdownItem{
|
|
8
9
|
label: string,
|
|
@@ -40,8 +41,8 @@ export class BPDropdownInputComponent extends BPInputComponent<string|number, BP
|
|
|
40
41
|
|
|
41
42
|
getUpdatedState(state: BPDropdownComponentState): BPDropdownComponentState {
|
|
42
43
|
const children = this.context.methods.getChildren(this.props.config)
|
|
43
|
-
const options: DropdownItem[] = children.map(value => {
|
|
44
|
-
const label = this.context.methods.getLabel(value)
|
|
44
|
+
const options: DropdownItem[] = children.map((value, i) => {
|
|
45
|
+
const label = cleanLabel(this.context.methods.getLabel(value)) || `Option ${i}`
|
|
45
46
|
return {label, value: value!.value ?? label}
|
|
46
47
|
})
|
|
47
48
|
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
display: flex;
|
|
28
28
|
flex-direction: column;
|
|
29
29
|
background-color: $light-gray4 !important;
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
//border-top: #7c7c7c7c 1px solid !important;
|
|
33
|
+
//border-bottom: #7c7c7c7c 1px solid !important;
|
|
30
34
|
}
|
|
31
35
|
.bp5-dark .folder-card {
|
|
32
36
|
background-color: $dark-gray1 !important;
|
|
@@ -44,6 +48,9 @@
|
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
.folder-trigger-button {
|
|
51
|
+
font-size: 12px !important;
|
|
52
|
+
font-weight: 550 !important;
|
|
53
|
+
|
|
47
54
|
margin-top: 1px;
|
|
48
55
|
display: flex;
|
|
49
56
|
align-items: center;
|
|
@@ -76,7 +83,7 @@
|
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
&.folder-trigger-button-expanded{
|
|
79
|
-
background-color: $dark-gray2 !important;
|
|
86
|
+
//background-color: $dark-gray2 !important;
|
|
80
87
|
}
|
|
81
88
|
}
|
|
82
89
|
|
|
@@ -119,3 +126,12 @@
|
|
|
119
126
|
}
|
|
120
127
|
}
|
|
121
128
|
|
|
129
|
+
.folder-card{
|
|
130
|
+
.bp5-input-group .bp5-input{
|
|
131
|
+
font-size: var(--pt-font-size-small);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.bp5-button{
|
|
135
|
+
font-size: var(--pt-font-size-small);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -90,7 +90,8 @@ export const FolderHeadCard: React.FC<React.PropsWithChildren<{ open: boolean, l
|
|
|
90
90
|
disabled={props.disabled}
|
|
91
91
|
small={props.minimal}
|
|
92
92
|
style={props.level ? {marginLeft: "6px"} : {fontSize: "0.95rem", paddingTop: "8px", paddingBottom: "8px"}}
|
|
93
|
-
intent={props.open ? Intent.PRIMARY : Intent.NONE}
|
|
93
|
+
// intent={props.open ? Intent.PRIMARY : Intent.NONE}
|
|
94
|
+
intent={Intent.NONE}
|
|
94
95
|
// icon={props.enabled !== undefined && <span style={{minWidth: '20px'}}></span>} // adding a span here will center the text in the button
|
|
95
96
|
icon={(
|
|
96
97
|
<>
|
|
@@ -99,7 +100,8 @@ export const FolderHeadCard: React.FC<React.PropsWithChildren<{ open: boolean, l
|
|
|
99
100
|
transition: "rotate 0.25s ease-in-out"
|
|
100
101
|
}}/>
|
|
101
102
|
</>
|
|
102
|
-
)}
|
|
103
|
+
)}
|
|
104
|
+
>{props.label}
|
|
103
105
|
</Button>
|
|
104
106
|
{hasEnabled && <Checkbox
|
|
105
107
|
style={{margin: 0, position: 'absolute', left: '10px'}}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {BPComponent, BPComponentProps, BPComponentState, UiConfigRendererContextType} from "./BPComponent";
|
|
2
|
+
import {cleanLabel} from "../utils";
|
|
2
3
|
|
|
3
4
|
export type BPLabelledComponentState = BPComponentState & {
|
|
4
5
|
label: string
|
|
@@ -12,8 +13,7 @@ export abstract class BPLabelledComponent<TValue, TState, TProps extends BPCompo
|
|
|
12
13
|
getUpdatedState(state: TState & BPLabelledComponentState): TState & BPLabelledComponentState {
|
|
13
14
|
return super.getUpdatedState({
|
|
14
15
|
...state,
|
|
15
|
-
label: this.context.methods.getLabel(this.props.config) || state.label,
|
|
16
|
+
label: cleanLabel(this.context.methods.getLabel(this.props.config)) || state.label,
|
|
16
17
|
})
|
|
17
18
|
}
|
|
18
|
-
|
|
19
19
|
}
|
|
@@ -291,7 +291,7 @@ export class ExtendedNumericInput extends React.PureComponent<Props, IExtendedNu
|
|
|
291
291
|
return (+value).toString();
|
|
292
292
|
};
|
|
293
293
|
|
|
294
|
-
private roundValue = (value: number, precision: number =
|
|
294
|
+
private roundValue = (value: number, precision: number = 6) => {
|
|
295
295
|
// round to at most two decimal places
|
|
296
296
|
return Math.round(value * 10 ** precision) / 10 ** precision;
|
|
297
297
|
};
|
|
@@ -45,7 +45,6 @@ import {
|
|
|
45
45
|
parseStringToStringNumber,
|
|
46
46
|
sanitizeNumericInput,
|
|
47
47
|
toLocaleString,
|
|
48
|
-
toMaxPrecision,
|
|
49
48
|
} from "@blueprintjs/core/src/components/forms/numericInputUtils";
|
|
50
49
|
|
|
51
50
|
export interface NumericInputProps extends InputSharedProps {
|
|
@@ -174,7 +173,7 @@ export interface NumericInputState {
|
|
|
174
173
|
prevMinProp?: number;
|
|
175
174
|
prevMaxProp?: number;
|
|
176
175
|
shouldSelectAfterUpdate: boolean;
|
|
177
|
-
stepMaxPrecision: number;
|
|
176
|
+
// stepMaxPrecision: number;
|
|
178
177
|
value: string;
|
|
179
178
|
}
|
|
180
179
|
|
|
@@ -241,19 +240,19 @@ export class NumericInput extends AbstractPureComponent<HTMLInputProps & Numeric
|
|
|
241
240
|
// in controlled mode, use props.value
|
|
242
241
|
// in uncontrolled mode, if state.value has not been assigned yet (upon initial mount), use props.defaultValue
|
|
243
242
|
const value = props.value?.toString() ?? state.value;
|
|
244
|
-
const stepMaxPrecision = NumericInput.getStepMaxPrecision(props);
|
|
243
|
+
// const stepMaxPrecision = NumericInput.getStepMaxPrecision(props);
|
|
245
244
|
|
|
246
245
|
const sanitizedValue =
|
|
247
246
|
value !== NumericInput.VALUE_EMPTY
|
|
248
|
-
? NumericInput.roundAndClampValue(value, stepMaxPrecision
|
|
247
|
+
? NumericInput.roundAndClampValue(value, /*stepMaxPrecision,*/ props.min, props.max, 0, props.locale)
|
|
249
248
|
: NumericInput.VALUE_EMPTY;
|
|
250
249
|
|
|
251
250
|
// if a new min and max were provided that cause the existing value to fall
|
|
252
251
|
// outside of the new bounds, then clamp the value to the new valid range.
|
|
253
252
|
if (didBoundsChange && sanitizedValue !== state.value) {
|
|
254
|
-
return { ...nextState, stepMaxPrecision
|
|
253
|
+
return { ...nextState, /*stepMaxPrecision,*/ value: sanitizedValue };
|
|
255
254
|
}
|
|
256
|
-
return { ...nextState, stepMaxPrecision
|
|
255
|
+
return { ...nextState, /*stepMaxPrecision,*/ value };
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
private static CONTINUOUS_CHANGE_DELAY = 300;
|
|
@@ -262,17 +261,17 @@ export class NumericInput extends AbstractPureComponent<HTMLInputProps & Numeric
|
|
|
262
261
|
|
|
263
262
|
// Value Helpers
|
|
264
263
|
// =============
|
|
265
|
-
private static getStepMaxPrecision(props: HTMLInputProps & NumericInputProps) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
264
|
+
// private static getStepMaxPrecision(props: HTMLInputProps & NumericInputProps) {
|
|
265
|
+
// if (props.minorStepSize != null) {
|
|
266
|
+
// return Utils.countDecimalPlaces(props.minorStepSize);
|
|
267
|
+
// } else {
|
|
268
|
+
// return Utils.countDecimalPlaces(props.stepSize!);
|
|
269
|
+
// }
|
|
270
|
+
// }
|
|
272
271
|
|
|
273
272
|
private static roundAndClampValue(
|
|
274
273
|
value: string,
|
|
275
|
-
stepMaxPrecision: number,
|
|
274
|
+
// stepMaxPrecision: number,
|
|
276
275
|
min: number | undefined,
|
|
277
276
|
max: number | undefined,
|
|
278
277
|
delta = 0,
|
|
@@ -282,7 +281,8 @@ export class NumericInput extends AbstractPureComponent<HTMLInputProps & Numeric
|
|
|
282
281
|
return NumericInput.VALUE_EMPTY;
|
|
283
282
|
}
|
|
284
283
|
const currentValue = parseStringToStringNumber(value, locale);
|
|
285
|
-
const nextValue = toMaxPrecision(Number(currentValue) + delta, stepMaxPrecision);
|
|
284
|
+
// const nextValue = toMaxPrecision(Number(currentValue) + delta, stepMaxPrecision);
|
|
285
|
+
const nextValue = (Number(currentValue) + delta);
|
|
286
286
|
const clampedValue = clampValue(nextValue, min, max);
|
|
287
287
|
return toLocaleString(clampedValue, locale);
|
|
288
288
|
}
|
|
@@ -290,7 +290,7 @@ export class NumericInput extends AbstractPureComponent<HTMLInputProps & Numeric
|
|
|
290
290
|
public state: NumericInputState = {
|
|
291
291
|
currentImeInputInvalid: false,
|
|
292
292
|
shouldSelectAfterUpdate: false,
|
|
293
|
-
stepMaxPrecision: NumericInput.getStepMaxPrecision(this.props),
|
|
293
|
+
// stepMaxPrecision: NumericInput.getStepMaxPrecision(this.props),
|
|
294
294
|
value: getValueOrEmptyValue(this.props.value ?? this.props.defaultValue),
|
|
295
295
|
};
|
|
296
296
|
|
|
@@ -664,7 +664,7 @@ export class NumericInput extends AbstractPureComponent<HTMLInputProps & Numeric
|
|
|
664
664
|
private roundAndClampValue(value: string, delta = 0) {
|
|
665
665
|
return NumericInput.roundAndClampValue(
|
|
666
666
|
value,
|
|
667
|
-
this.state.stepMaxPrecision,
|
|
667
|
+
// this.state.stepMaxPrecision,
|
|
668
668
|
this.props.min,
|
|
669
669
|
this.props.max,
|
|
670
670
|
delta,
|
package/src/renderer.scss
CHANGED
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
max-width: calc(8 * $pt-font-size-small);
|
|
72
72
|
min-width: calc(8 * $pt-font-size-small);
|
|
73
73
|
width: calc(8 * $pt-font-size-small);
|
|
74
|
-
font-size: $pt-font-size-small;
|
|
74
|
+
//font-size: $pt-font-size-small;
|
|
75
75
|
height: $pt-input-height;
|
|
76
76
|
line-height: normal;
|
|
77
77
|
|
|
@@ -85,6 +85,9 @@
|
|
|
85
85
|
.bp5-dark & {
|
|
86
86
|
color: $gray5;
|
|
87
87
|
}
|
|
88
|
+
|
|
89
|
+
font-size: 11px !important;
|
|
90
|
+
font-weight: 450 !important;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
.switch{
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
// todo move to uiConfigMethods
|
|
3
|
+
export function cleanLabel(varName?: string): string|undefined {
|
|
4
|
+
if (!varName || typeof varName !== 'string') {
|
|
5
|
+
return varName;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let result = varName.trim();
|
|
9
|
+
if (!result) return '';
|
|
10
|
+
if(result.includes(' ')) return result; // already has spaces
|
|
11
|
+
|
|
12
|
+
result = result.replace(/_/g, ' ');
|
|
13
|
+
|
|
14
|
+
// Insert spaces before uppercase letters (camelCase handling)
|
|
15
|
+
// First handle sequences like "XMLHttp" -> "XML Http"
|
|
16
|
+
result = result.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2');
|
|
17
|
+
// Then handle regular camelCase like "firstName" -> "first Name"
|
|
18
|
+
result = result.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
19
|
+
|
|
20
|
+
// Insert spaces before numbers that follow letters
|
|
21
|
+
result = result.replace(/([a-zA-Z])(\d)/g, '$1 $2');
|
|
22
|
+
|
|
23
|
+
// Insert spaces after numbers that are followed by letters
|
|
24
|
+
result = result.replace(/(\d)([a-zA-Z])/g, '$1 $2');
|
|
25
|
+
|
|
26
|
+
// Split into words, capitalize first letter of each word, and join with spaces
|
|
27
|
+
const words = result.split(/\s+/).filter(word => word.length > 0);
|
|
28
|
+
const capitalizedWords = words.map(word =>
|
|
29
|
+
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
return capitalizedWords.join(' ');
|
|
34
|
+
}
|