@rokkit/core 1.0.0-next.104 → 1.0.0-next.106
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/calendar.d.ts +10 -0
- package/dist/connector.d.ts +8 -0
- package/dist/events.d.ts +12 -0
- package/dist/field-mapper.d.ts +59 -17
- package/dist/index.d.ts +6 -0
- package/dist/mapped-items.d.ts +14 -0
- package/dist/string.d.ts +1 -1
- package/dist/theme.d.ts +52 -0
- package/dist/ticks.d.ts +10 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +12 -0
- package/package.json +8 -6
- package/src/calendar.js +44 -0
- package/src/connector.js +34 -0
- package/src/constants.js +8 -3
- package/src/events.js +32 -0
- package/src/field-mapper.js +151 -42
- package/src/index.js +7 -0
- package/src/key-event-map.js +4 -3
- package/src/mapped-items.js +22 -0
- package/src/theme.js +205 -0
- package/src/ticks.js +26 -0
- package/src/types.js +4 -0
- package/src/utils.js +18 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the days in the month.
|
|
3
|
+
*
|
|
4
|
+
* @param {Date} value
|
|
5
|
+
* @param {Array} holidays
|
|
6
|
+
* @param {boolean} fixed
|
|
7
|
+
* @returns {import('./types').CalendarDay[]}
|
|
8
|
+
*/
|
|
9
|
+
export function getCalendarDays(value: Date, holidays?: any[], fixed?: boolean): import("./types").CalendarDay[];
|
|
10
|
+
export const weekdays: string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constructs an array of line types for tree visualization
|
|
3
|
+
* @param {boolean} hasChildren - Whether the node has children
|
|
4
|
+
* @param {import('./types').LineType[]} parentTypes - Types from parent nodes
|
|
5
|
+
* @param {import('./types').LineType} position - Current position type
|
|
6
|
+
* @returns {import('./types').LineType[]} Array of line types
|
|
7
|
+
*/
|
|
8
|
+
export function getLineTypes(hasChildren?: boolean, parentTypes?: import("./types").LineType[], position?: import("./types").LineType): import("./types").LineType[];
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an emitter object from the given properties.
|
|
3
|
+
*
|
|
4
|
+
* - Filters attributes that start with 'on' and are functions,
|
|
5
|
+
* - Returns an object with keys that are the event names (without the 'on' prefix)
|
|
6
|
+
* - If a default event is not present in the props, it will be set to a no-op function.
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} props - The properties object to filter.
|
|
9
|
+
* @param {Array<string>} defaults - An array of default events.
|
|
10
|
+
* @returns {import('./types.js').EventHandlers} The emitter object.
|
|
11
|
+
*/
|
|
12
|
+
export function createEmitter(props: Object, defaults?: Array<string>): import("./types.js").EventHandlers;
|
package/dist/field-mapper.d.ts
CHANGED
|
@@ -1,20 +1,62 @@
|
|
|
1
1
|
export class FieldMapper {
|
|
2
|
-
constructor(fields?: any,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
2
|
+
constructor(fields?: any, componentMap?: {});
|
|
3
|
+
hasIcon: ((obj: unknown) => obj is {
|
|
4
|
+
[x: string]: unknown;
|
|
5
|
+
}) | undefined;
|
|
6
|
+
hasImage: ((obj: unknown) => obj is {
|
|
7
|
+
[x: string]: unknown;
|
|
8
|
+
}) | undefined;
|
|
9
|
+
hasText: ((obj: unknown) => obj is {
|
|
10
|
+
[x: string]: unknown;
|
|
11
|
+
}) | undefined;
|
|
12
|
+
hasValue: ((obj: unknown) => obj is {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
}) | undefined;
|
|
15
|
+
hasLabel: ((obj: unknown) => obj is {
|
|
16
|
+
[x: string]: unknown;
|
|
17
|
+
}) | undefined;
|
|
18
|
+
hasComponent: ((obj: unknown) => obj is {
|
|
19
|
+
[x: string]: unknown;
|
|
20
|
+
}) | undefined;
|
|
21
|
+
hasCurrency: ((obj: unknown) => obj is {
|
|
22
|
+
[x: string]: unknown;
|
|
23
|
+
}) | undefined;
|
|
24
|
+
withPrefix: ((x: any) => string) | undefined;
|
|
25
|
+
excludeFlags: (<U extends Partial<Record<any, any>>>(obj: any extends keyof U ? U : never) => any extends keyof U ? Omit<U, any> : never) | undefined;
|
|
26
|
+
set fields(fields: any);
|
|
27
|
+
get fields(): any;
|
|
28
|
+
set componentMap(components: {});
|
|
29
|
+
get componentMap(): {};
|
|
30
|
+
getComponent(value: any): any;
|
|
31
|
+
getIcon(value: any): string | null;
|
|
32
|
+
getImage(value: any): any;
|
|
33
|
+
getValue(value: any): any;
|
|
34
|
+
getText(value: any): any;
|
|
35
|
+
getLabel(value: any): any;
|
|
36
|
+
getAttribute(value: any, attr: any): any;
|
|
37
|
+
getFormattedText(value: any, formatter: any): any;
|
|
38
|
+
hasChildren(item: any): item is never;
|
|
39
|
+
isExpanded(item: any): false;
|
|
40
|
+
isHidden(item: any): unknown;
|
|
17
41
|
isNested(items: any): boolean;
|
|
18
|
-
|
|
19
|
-
|
|
42
|
+
toggleVisibility(items: any, visible: any): void;
|
|
43
|
+
toggleExpansion(item: any): void;
|
|
44
|
+
getChildren(item: any): never[];
|
|
45
|
+
/**
|
|
46
|
+
* Finds children by an index path
|
|
47
|
+
*
|
|
48
|
+
* @param {Array<Object>} items
|
|
49
|
+
* @param {Array<number>} path
|
|
50
|
+
* @returns {Array<Object>}
|
|
51
|
+
*/
|
|
52
|
+
getChildrenByPath(items: Array<Object>, path?: Array<number>): Array<Object>;
|
|
53
|
+
/**
|
|
54
|
+
* Finds an item by an index path
|
|
55
|
+
*
|
|
56
|
+
* @param {Array<Object>} items
|
|
57
|
+
* @param {Array<number>} path
|
|
58
|
+
* @returns {Object|null}
|
|
59
|
+
*/
|
|
60
|
+
getItemByPath(items: Array<Object>, path?: Array<number>): Object | null;
|
|
61
|
+
#private;
|
|
20
62
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,10 @@ export * from "./constants.js";
|
|
|
3
3
|
export * from "./utils.js";
|
|
4
4
|
export * from "./nested.js";
|
|
5
5
|
export * from "./string.js";
|
|
6
|
+
export * from "./theme.js";
|
|
6
7
|
export { FieldMapper } from "./field-mapper.js";
|
|
8
|
+
export { createEmitter } from "./events.js";
|
|
9
|
+
export { getLineTypes } from "./connector.js";
|
|
10
|
+
export { generateTicks } from "./ticks.js";
|
|
11
|
+
export { getItemAtIndex, getIndexForItem } from "./mapped-items.js";
|
|
12
|
+
export { weekdays, getCalendarDays } from "./calendar.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get an item at a specific index
|
|
3
|
+
* @param {Array<any>} items
|
|
4
|
+
* @param {any} index
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export function getItemAtIndex(items: Array<any>, index: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* Get the index for an item in an array
|
|
10
|
+
* @param {Array<any} items
|
|
11
|
+
* @param {any} item
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export function getIndexForItem(items: Array<any>, item: any): number;
|
package/dist/string.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export function toHyphenCase(text: string): string;
|
|
|
26
26
|
* @param {String} b
|
|
27
27
|
* @returns
|
|
28
28
|
*/
|
|
29
|
-
export function compareStrings(a: string, b: string):
|
|
29
|
+
export function compareStrings(a: string, b: string): 1 | 0 | -1;
|
|
30
30
|
/**
|
|
31
31
|
* Sort by splitting hyphen separated strings while keeping strings with same number of parts together
|
|
32
32
|
*
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate shades for a color using css varuable
|
|
3
|
+
*
|
|
4
|
+
* @param {string} name
|
|
5
|
+
* @param {string} modifier
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function shadesOf(name: string, modifier?: string): {
|
|
9
|
+
DEFAULT: any;
|
|
10
|
+
base: any;
|
|
11
|
+
inset: any;
|
|
12
|
+
subtle: any;
|
|
13
|
+
muted: any;
|
|
14
|
+
raised: any;
|
|
15
|
+
elevated: any;
|
|
16
|
+
floating: any;
|
|
17
|
+
contrast: any;
|
|
18
|
+
overlay: any;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Generate shades for a color using css varuable
|
|
22
|
+
*
|
|
23
|
+
* @param {string} name
|
|
24
|
+
* @param {string} modifier
|
|
25
|
+
* @returns {object}
|
|
26
|
+
*/
|
|
27
|
+
export function stateColors(name: string, modifier?: string): object;
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {string} modifier
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
export function themeColors(modifier?: string): {};
|
|
34
|
+
/**
|
|
35
|
+
* Generates contrast colors for light and dark modes based on a given palette. Each color variant in the
|
|
36
|
+
* palette is mapped to either a light or dark contrast color depending on the shade's value.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} [light='#ffffff'] - The default light color used when the shade is >= 500 in light mode or <= 500 in dark mode.
|
|
39
|
+
* @param {string} [dark='#000000'] - The default dark color used when the shade is < 500 in light mode or > 500 in dark mode.
|
|
40
|
+
* @param {Array<string>} [palette=defaultPalette] - An array of color variant names to generate contrast colors for.
|
|
41
|
+
* @returns {Array<Object>} An array containing contrast color rules organized by light and dark modes for each variant in the palette.
|
|
42
|
+
*/
|
|
43
|
+
export function contrastColors(light?: string, dark?: string, palette?: Array<string>): Array<Object>;
|
|
44
|
+
/**
|
|
45
|
+
* Constructs and returns the light and dark theme variants based on provided color mapping and color definitions.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} name - The base name for the theme, defaults to 'rokkit' if not provided.
|
|
48
|
+
* @param {Object} [mapping=defaultThemeMapping] - An object mapping variant names to color property names.
|
|
49
|
+
* @param {Object} [colors=defaultColors] - The object containing default color definitions.
|
|
50
|
+
* @returns {Array<Array>} An array containing two arrays, one for the light theme variant and another for the dark theme.
|
|
51
|
+
*/
|
|
52
|
+
export function themeRules(name?: string, mapping?: Object, colors?: Object): Array<any[]>;
|
package/dist/ticks.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates an array of tick marks for a range of values.
|
|
3
|
+
*
|
|
4
|
+
* @param {number} lowerBound - The lower bound of the range.
|
|
5
|
+
* @param {number} upperBound - The upper bound of the range.
|
|
6
|
+
* @param {number} [minorTickStep=upperBound-lowerBound] - The step size for minor ticks.
|
|
7
|
+
* @param {number} [majorTickStep=1] - The step size for major ticks.
|
|
8
|
+
* @returns {import('./types').TickMark[]>} An array of tick mark objects.
|
|
9
|
+
*/
|
|
10
|
+
export function generateTicks(lowerBound: number, upperBound: number, minorTickStep?: number, majorTickStep?: number): import("./types").TickMark[];
|
package/dist/types.d.ts
CHANGED
package/dist/utils.d.ts
CHANGED
|
@@ -47,3 +47,15 @@ export function iconShortcuts(icons: string[], collection: string, variants: str
|
|
|
47
47
|
* @returns {string|number}
|
|
48
48
|
*/
|
|
49
49
|
export function scaledPath(size: number, x: string | number): string | number;
|
|
50
|
+
/**
|
|
51
|
+
* Gets a key string from path
|
|
52
|
+
* @param {string[]} path
|
|
53
|
+
* @returns {string}
|
|
54
|
+
*/
|
|
55
|
+
export function getKeyFromPath(path: string[]): string;
|
|
56
|
+
/**
|
|
57
|
+
* Gets a path array from key string
|
|
58
|
+
* @param {string} key
|
|
59
|
+
* @returns {string[]}
|
|
60
|
+
*/
|
|
61
|
+
export function getPathFromKey(key: string): string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.106",
|
|
4
4
|
"description": "Contains core utility functions and classes that can be used in various components.",
|
|
5
5
|
"author": "Jerry Thomas <me@jerrythomas.name>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"prepublishOnly": "tsc --project tsconfig.build.json",
|
|
14
|
+
"clean": "rm -rf dist",
|
|
15
|
+
"build": "bun clean && bun prepublishOnly"
|
|
16
|
+
},
|
|
12
17
|
"files": [
|
|
13
18
|
"src/**/*.js",
|
|
14
19
|
"src/**/*.json",
|
|
@@ -23,10 +28,7 @@
|
|
|
23
28
|
}
|
|
24
29
|
},
|
|
25
30
|
"dependencies": {
|
|
31
|
+
"date-fns": "^4.1.0",
|
|
26
32
|
"ramda": "^0.30.1"
|
|
27
|
-
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"clean": "rm -rf dist",
|
|
30
|
-
"build": "pnpm clean && pnpm prepublishOnly"
|
|
31
33
|
}
|
|
32
|
-
}
|
|
34
|
+
}
|
package/src/calendar.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getDay, getMonth, getYear, getDaysInMonth, format, isWeekend } from 'date-fns'
|
|
2
|
+
|
|
3
|
+
export const weekdays = [
|
|
4
|
+
'Sunday',
|
|
5
|
+
'Monday',
|
|
6
|
+
'Tuesday',
|
|
7
|
+
'Wednesday',
|
|
8
|
+
'Thursday',
|
|
9
|
+
'Friday',
|
|
10
|
+
'Saturday'
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the days in the month.
|
|
15
|
+
*
|
|
16
|
+
* @param {Date} value
|
|
17
|
+
* @param {Array} holidays
|
|
18
|
+
* @param {boolean} fixed
|
|
19
|
+
* @returns {import('./types').CalendarDay[]}
|
|
20
|
+
*/
|
|
21
|
+
export function getCalendarDays(value, holidays = [], fixed = false) {
|
|
22
|
+
const month = getMonth(value)
|
|
23
|
+
const year = getYear(value)
|
|
24
|
+
const offset = getDay(new Date(year, month, 1)) + 1
|
|
25
|
+
|
|
26
|
+
holidays = holidays.map((x) => format(new Date(x), 'yyyy-MMM-dd'))
|
|
27
|
+
let days = Array.from({ length: getDaysInMonth(value) }, (_, i) => ({
|
|
28
|
+
day: i + 1,
|
|
29
|
+
offset: i === 0 ? offset : 0,
|
|
30
|
+
date: new Date(year, month, i + 1)
|
|
31
|
+
})).map((x) => ({
|
|
32
|
+
...x,
|
|
33
|
+
text: format(x.date, 'yyyy-MMM-dd'),
|
|
34
|
+
weekend: isWeekend(x.date),
|
|
35
|
+
holiday: holidays.includes(format(x.date, 'yyyy-MMM-dd'))
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
if (fixed && days[0].offset > 4) {
|
|
39
|
+
const n = 5 * 7 - days[0].offset
|
|
40
|
+
days = [...days.slice(n + 1), ...days.slice(0, n + 1)]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return days
|
|
44
|
+
}
|
package/src/connector.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const LINE_TYPES = {
|
|
2
|
+
CHILD: 'child',
|
|
3
|
+
LAST: 'last',
|
|
4
|
+
SIBLING: 'sibling',
|
|
5
|
+
EMPTY: 'empty',
|
|
6
|
+
ICON: 'icon'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const nextType = {
|
|
10
|
+
[LINE_TYPES.CHILD]: LINE_TYPES.SIBLING,
|
|
11
|
+
[LINE_TYPES.LAST]: LINE_TYPES.EMPTY,
|
|
12
|
+
[LINE_TYPES.SIBLING]: LINE_TYPES.SIBLING,
|
|
13
|
+
[LINE_TYPES.EMPTY]: LINE_TYPES.EMPTY
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructs an array of line types for tree visualization
|
|
18
|
+
* @param {boolean} hasChildren - Whether the node has children
|
|
19
|
+
* @param {import('./types').LineType[]} parentTypes - Types from parent nodes
|
|
20
|
+
* @param {import('./types').LineType} position - Current position type
|
|
21
|
+
* @returns {import('./types').LineType[]} Array of line types
|
|
22
|
+
*/
|
|
23
|
+
export function getLineTypes(hasChildren = false, parentTypes = [], position = LINE_TYPES.CHILD) {
|
|
24
|
+
return parentTypes
|
|
25
|
+
.reduce((acc, type, index) => {
|
|
26
|
+
// For all but the last parent type, convert to next type
|
|
27
|
+
if (index < parentTypes.length - 1) {
|
|
28
|
+
return [...acc, nextType[type]]
|
|
29
|
+
}
|
|
30
|
+
// For the last parent type, use the position
|
|
31
|
+
return [...acc, position]
|
|
32
|
+
}, [])
|
|
33
|
+
.concat(hasChildren ? LINE_TYPES.ICON : LINE_TYPES.EMPTY)
|
|
34
|
+
}
|
package/src/constants.js
CHANGED
|
@@ -18,11 +18,16 @@ export const defaultFields = {
|
|
|
18
18
|
props: 'props',
|
|
19
19
|
target: 'target',
|
|
20
20
|
state: 'state',
|
|
21
|
-
isOpen: '_open',
|
|
22
|
-
isDeleted: '_deleted',
|
|
23
21
|
level: 'level',
|
|
24
22
|
parent: 'parent',
|
|
25
|
-
currency: 'currency'
|
|
23
|
+
currency: 'currency',
|
|
24
|
+
label: 'label',
|
|
25
|
+
/* flag fields */
|
|
26
|
+
isSelected: '_selected',
|
|
27
|
+
isHidden: '_hidden',
|
|
28
|
+
isOpen: '_open',
|
|
29
|
+
isDeleted: '_deleted',
|
|
30
|
+
isFiltered: '_filtered'
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
export const defaultIcons = [
|
package/src/events.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { noop } from './utils.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates an emitter object from the given properties.
|
|
5
|
+
*
|
|
6
|
+
* - Filters attributes that start with 'on' and are functions,
|
|
7
|
+
* - Returns an object with keys that are the event names (without the 'on' prefix)
|
|
8
|
+
* - If a default event is not present in the props, it will be set to a no-op function.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} props - The properties object to filter.
|
|
11
|
+
* @param {Array<string>} defaults - An array of default events.
|
|
12
|
+
* @returns {import('./types.js').EventHandlers} The emitter object.
|
|
13
|
+
*/
|
|
14
|
+
export function createEmitter(props, defaults = []) {
|
|
15
|
+
const emit = {}
|
|
16
|
+
|
|
17
|
+
// Filter and add functions that start with 'on'
|
|
18
|
+
Object.entries(props)
|
|
19
|
+
.filter(([key, value]) => key.startsWith('on') && typeof value === 'function')
|
|
20
|
+
.forEach(([key, value]) => {
|
|
21
|
+
emit[key.slice(2)] = value
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Add default events with no-op function if not present
|
|
25
|
+
defaults.forEach((event) => {
|
|
26
|
+
if (!emit[event]) {
|
|
27
|
+
emit[event] = noop
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return emit
|
|
32
|
+
}
|
package/src/field-mapper.js
CHANGED
|
@@ -1,81 +1,190 @@
|
|
|
1
|
-
import { defaultFields } from './constants'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
getIcon,
|
|
5
|
-
getValue,
|
|
6
|
-
getText,
|
|
7
|
-
getAttribute,
|
|
8
|
-
getFormattedText,
|
|
9
|
-
hasChildren,
|
|
10
|
-
isExpanded
|
|
11
|
-
} from './mapping'
|
|
12
|
-
import { has } from 'ramda'
|
|
1
|
+
import { defaultFields } from './constants.js'
|
|
2
|
+
import { isNil, has, omit } from 'ramda'
|
|
3
|
+
import { isObject } from './utils.js'
|
|
13
4
|
|
|
14
5
|
export class FieldMapper {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(fields = defaultFields,
|
|
19
|
-
this
|
|
20
|
-
this
|
|
6
|
+
#fields = { ...defaultFields }
|
|
7
|
+
#componentMap = {}
|
|
8
|
+
|
|
9
|
+
constructor(fields = defaultFields, componentMap = {}) {
|
|
10
|
+
this.#updateFields(fields)
|
|
11
|
+
this.#updateComponentMap(componentMap)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#updateFields(fields) {
|
|
15
|
+
Object.keys(fields).forEach((key) => {
|
|
16
|
+
this.#fields[key] = fields[key]
|
|
17
|
+
})
|
|
18
|
+
this.hasIcon = has(this.#fields.icon)
|
|
19
|
+
this.hasImage = has(this.#fields.image)
|
|
20
|
+
this.hasText = has(this.#fields.text)
|
|
21
|
+
this.hasValue = has(this.#fields.value)
|
|
22
|
+
this.hasLabel = has(this.#fields.label)
|
|
23
|
+
this.hasComponent = has(this.#fields.component)
|
|
24
|
+
this.hasCurrency = has(this.#fields.currency)
|
|
25
|
+
this.withPrefix = (x) => [this.#fields.iconPrefix, x].join('-').replace(/^-+/g, '')
|
|
26
|
+
this.excludeFlags = omit([
|
|
27
|
+
this.#fields.isDeleted,
|
|
28
|
+
this.#fields.isHidden,
|
|
29
|
+
this.#fields.isSelected,
|
|
30
|
+
this.#fields.isFiltered,
|
|
31
|
+
this.#fields.isOpen
|
|
32
|
+
])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#updateComponentMap(components) {
|
|
36
|
+
if (typeof components === 'object' && components) {
|
|
37
|
+
Object.keys(components).forEach((key) => {
|
|
38
|
+
this.#componentMap[key] = components[key]
|
|
39
|
+
})
|
|
40
|
+
}
|
|
21
41
|
}
|
|
22
42
|
|
|
23
43
|
get fields() {
|
|
24
|
-
return this
|
|
44
|
+
return this.#fields
|
|
25
45
|
}
|
|
26
46
|
|
|
27
47
|
set fields(fields) {
|
|
28
|
-
this
|
|
48
|
+
this.#updateFields(fields)
|
|
29
49
|
}
|
|
30
50
|
|
|
31
|
-
get
|
|
32
|
-
return this
|
|
51
|
+
get componentMap() {
|
|
52
|
+
return this.#componentMap
|
|
33
53
|
}
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
|
|
55
|
+
set componentMap(components) {
|
|
56
|
+
this.#updateComponentMap(components)
|
|
36
57
|
}
|
|
37
58
|
|
|
38
59
|
getComponent(value) {
|
|
39
|
-
|
|
60
|
+
if (this.hasComponent(value))
|
|
61
|
+
return this.componentMap[value[this.fields.component]] ?? this.componentMap.default
|
|
62
|
+
return this.componentMap.default
|
|
40
63
|
}
|
|
41
64
|
|
|
42
65
|
getIcon(value) {
|
|
43
|
-
|
|
66
|
+
if (!this.hasIcon(value)) return null
|
|
67
|
+
const icon = value[this.fields.icon]
|
|
68
|
+
if (isObject(icon)) return this.withPrefix(icon[value[this.fields.state]])
|
|
69
|
+
return this.withPrefix(icon)
|
|
70
|
+
}
|
|
71
|
+
getImage(value) {
|
|
72
|
+
return this.getAttribute(value, 'image')
|
|
44
73
|
}
|
|
45
74
|
|
|
46
|
-
getValue(
|
|
47
|
-
|
|
75
|
+
getValue(value) {
|
|
76
|
+
if (this.hasValue(value)) {
|
|
77
|
+
return value[this.fields.value]
|
|
78
|
+
}
|
|
79
|
+
return value
|
|
48
80
|
}
|
|
49
81
|
|
|
50
|
-
getText(
|
|
51
|
-
|
|
82
|
+
getText(value) {
|
|
83
|
+
if (this.hasText(value)) {
|
|
84
|
+
return value[this.fields.text]
|
|
85
|
+
}
|
|
86
|
+
return typeof value === 'object' ? null : value
|
|
52
87
|
}
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
return getAttribute(
|
|
89
|
+
getLabel(value) {
|
|
90
|
+
return this.getAttribute(value, 'label') ?? this.getText(value)
|
|
56
91
|
}
|
|
57
92
|
|
|
58
|
-
|
|
59
|
-
|
|
93
|
+
getAttribute(value, attr) {
|
|
94
|
+
if (has(attr, this.fields)) {
|
|
95
|
+
return has(this.fields[attr], value) ? value[this.fields[attr]] : null
|
|
96
|
+
}
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getFormattedText(value, formatter) {
|
|
101
|
+
const text = this.getText(value)
|
|
102
|
+
if (isNil(text)) return ''
|
|
103
|
+
|
|
104
|
+
if (typeof formatter !== 'function') return text.toString()
|
|
105
|
+
|
|
106
|
+
if (this.hasCurrency(value)) {
|
|
107
|
+
return formatter(text, this.getAttribute(value, 'currency'))
|
|
108
|
+
}
|
|
109
|
+
return formatter(text)
|
|
60
110
|
}
|
|
61
111
|
|
|
62
112
|
hasChildren(item) {
|
|
63
|
-
return
|
|
113
|
+
return (
|
|
114
|
+
!isNil(item) &&
|
|
115
|
+
has(this.fields.children, item) &&
|
|
116
|
+
Array.isArray(item[this.fields.children]) &&
|
|
117
|
+
item[this.fields.children].length > 0
|
|
118
|
+
)
|
|
64
119
|
}
|
|
65
120
|
|
|
66
121
|
isExpanded(item) {
|
|
67
|
-
|
|
122
|
+
if (this.hasChildren(item)) {
|
|
123
|
+
return has(this.fields.isOpen, item) && item[this.fields.isOpen]
|
|
124
|
+
}
|
|
125
|
+
return false
|
|
68
126
|
}
|
|
69
127
|
|
|
70
|
-
|
|
71
|
-
return
|
|
128
|
+
isHidden(item) {
|
|
129
|
+
return has(this.fields.isHidden, item) && item[this.fields.isHidden]
|
|
72
130
|
}
|
|
73
131
|
|
|
74
|
-
|
|
75
|
-
return
|
|
132
|
+
isNested(items) {
|
|
133
|
+
return Array.isArray(items) && items.some((item) => this.hasChildren(item))
|
|
76
134
|
}
|
|
77
135
|
|
|
78
|
-
|
|
79
|
-
|
|
136
|
+
toggleVisibility(items, visible) {
|
|
137
|
+
items.forEach((item) => {
|
|
138
|
+
item[this.fields.isHidden] = !visible
|
|
139
|
+
if (this.hasChildren(item)) {
|
|
140
|
+
this.toggleVisibility(item[this.fields.children], visible && item[this.fields.isOpen])
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
toggleExpansion(item) {
|
|
146
|
+
if (this.hasChildren(item)) {
|
|
147
|
+
item[this.fields.isOpen] = !item[this.fields.isOpen]
|
|
148
|
+
this.toggleVisibility(item[this.fields.children], item[this.fields.isOpen])
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getChildren(item) {
|
|
153
|
+
return this.hasChildren(item) ? item[this.fields.children] : []
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Finds children by an index path
|
|
158
|
+
*
|
|
159
|
+
* @param {Array<Object>} items
|
|
160
|
+
* @param {Array<number>} path
|
|
161
|
+
* @returns {Array<Object>}
|
|
162
|
+
*/
|
|
163
|
+
getChildrenByPath(items, path = []) {
|
|
164
|
+
const result = path.reduce(
|
|
165
|
+
(children, index) => children?.[index]?.[this.fields.children],
|
|
166
|
+
items
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if (result === undefined) throw new Error('Invalid path')
|
|
170
|
+
return result
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Finds an item by an index path
|
|
175
|
+
*
|
|
176
|
+
* @param {Array<Object>} items
|
|
177
|
+
* @param {Array<number>} path
|
|
178
|
+
* @returns {Object|null}
|
|
179
|
+
*/
|
|
180
|
+
getItemByPath(items, path = []) {
|
|
181
|
+
// skipcq: JS-W1042 default undefined is needed
|
|
182
|
+
const result = path.reduce(
|
|
183
|
+
(item, index, i) => (i === 0 ? items?.[index] : item?.[this.fields.children]?.[index]),
|
|
184
|
+
undefined
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if (result === undefined) throw new Error('Invalid path')
|
|
188
|
+
return result
|
|
80
189
|
}
|
|
81
190
|
}
|
package/src/index.js
CHANGED
|
@@ -8,4 +8,11 @@ export * from './utils.js'
|
|
|
8
8
|
export * from './nested.js'
|
|
9
9
|
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
10
10
|
export * from './string.js'
|
|
11
|
+
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
12
|
+
export * from './theme.js'
|
|
11
13
|
export { FieldMapper } from './field-mapper.js'
|
|
14
|
+
export { getItemAtIndex, getIndexForItem } from './mapped-items.js'
|
|
15
|
+
export { createEmitter } from './events.js'
|
|
16
|
+
export { getLineTypes } from './connector.js'
|
|
17
|
+
export { weekdays, getCalendarDays } from './calendar.js'
|
|
18
|
+
export { generateTicks } from './ticks.js'
|
package/src/key-event-map.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { find, toPairs } from 'ramda'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Class to manage key event mappings.
|
|
@@ -26,10 +26,11 @@ export class KeyEventMap {
|
|
|
26
26
|
* @returns {string|null} - The event name or null if no match is found.
|
|
27
27
|
*/
|
|
28
28
|
getEventForKey(key) {
|
|
29
|
-
|
|
29
|
+
// eslint-disable-next-line no-unused-vars
|
|
30
|
+
const matchEvent = ([_, keys]) =>
|
|
30
31
|
(Array.isArray(keys) && keys.includes(key)) || (keys instanceof RegExp && keys.test(key))
|
|
31
32
|
|
|
32
|
-
const event =
|
|
33
|
+
const event = find(matchEvent, toPairs(this.mapping))
|
|
33
34
|
return event ? event[0] : null
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { equals, isNil } from 'ramda'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get an item at a specific index
|
|
5
|
+
* @param {Array<any>} items
|
|
6
|
+
* @param {any} index
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export function getItemAtIndex(items, index) {
|
|
10
|
+
if (isNil(index)) return null
|
|
11
|
+
return index >= 0 && index < items.length ? items[index] : null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the index for an item in an array
|
|
16
|
+
* @param {Array<any} items
|
|
17
|
+
* @param {any} item
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export function getIndexForItem(items, item) {
|
|
21
|
+
return items.findIndex((i) => equals(i, item))
|
|
22
|
+
}
|
package/src/theme.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { defaultThemeMapping, defaultColors, syntaxColors } from './constants.js'
|
|
2
|
+
import { shades, defaultPalette } from './colors/index.js'
|
|
3
|
+
|
|
4
|
+
const modifiers = {
|
|
5
|
+
hsl: (value) => `hsl(${value})`,
|
|
6
|
+
rgb: (value) => `rgb(${value})`,
|
|
7
|
+
none: (value) => value
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate shades for a color using css varuable
|
|
12
|
+
*
|
|
13
|
+
* @param {string} name
|
|
14
|
+
* @param {string} modifier
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
export function shadesOf(name, modifier = 'none') {
|
|
18
|
+
const fn = modifier in modifiers ? modifiers[modifier] : modifiers.none
|
|
19
|
+
|
|
20
|
+
return shades.reduce(
|
|
21
|
+
(result, shade) => ({
|
|
22
|
+
...result,
|
|
23
|
+
[shade]: fn(`var(--${name}-${shade})`)
|
|
24
|
+
}),
|
|
25
|
+
{
|
|
26
|
+
DEFAULT: fn(`var(--${name}-500)`),
|
|
27
|
+
base: fn(`var(--${name}-50)`),
|
|
28
|
+
inset: fn(`var(--${name}-100)`),
|
|
29
|
+
subtle: fn(`var(--${name}-200)`),
|
|
30
|
+
muted: fn(`var(--${name}-300)`),
|
|
31
|
+
raised: fn(`var(--${name}-400)`),
|
|
32
|
+
elevated: fn(`var(--${name}-600)`),
|
|
33
|
+
floating: fn(`var(--${name}-700)`),
|
|
34
|
+
contrast: fn(`var(--${name}-800)`),
|
|
35
|
+
overlay: fn(`var(--${name}-900)`)
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate shades for a color using css varuable
|
|
42
|
+
*
|
|
43
|
+
* @param {string} name
|
|
44
|
+
* @param {string} modifier
|
|
45
|
+
* @returns {object}
|
|
46
|
+
*/
|
|
47
|
+
export function stateColors(name, modifier = 'none') {
|
|
48
|
+
const fn = modifier in modifiers ? modifiers[modifier] : modifiers.none
|
|
49
|
+
return {
|
|
50
|
+
DEFAULT: fn(`var(--${name}-500)`),
|
|
51
|
+
light: fn(`var(--${name}-200)`),
|
|
52
|
+
dark: fn(`var(--${name}-700)`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {string} modifier
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
export function themeColors(modifier = 'none') {
|
|
62
|
+
const fn = modifier in modifiers ? modifiers[modifier] : modifiers.none
|
|
63
|
+
|
|
64
|
+
const states = ['info', 'danger', 'warning', 'success', 'error']
|
|
65
|
+
const variants = ['neutral', 'primary', 'secondary', 'accent']
|
|
66
|
+
let colors = states.reduce(
|
|
67
|
+
(acc, state) => ({ ...acc, [state]: stateColors(state, modifier) }),
|
|
68
|
+
{}
|
|
69
|
+
)
|
|
70
|
+
colors = variants.reduce(
|
|
71
|
+
(acc, variant) => ({ ...acc, [variant]: shadesOf(variant, modifier) }),
|
|
72
|
+
colors
|
|
73
|
+
)
|
|
74
|
+
colors.neutral = {
|
|
75
|
+
...colors.neutral,
|
|
76
|
+
// contrast: fn(`var(--neutral-800)`),
|
|
77
|
+
zebra: fn('var(--neutral-zebra)')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return colors
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates an array of shade mapping objects for a given theme variant and mode.
|
|
85
|
+
* Each object represents a CSS custom property (variable) with its value set based on a provided condition.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} variant - The name of the theme variant (e.g., 'primary', 'secondary').
|
|
88
|
+
* @param {'light' | 'dark'} mode - The theme mode for which the mappings are being created.
|
|
89
|
+
* @param {function(number): string} valueCondition - A function that takes a shade value and returns the color value
|
|
90
|
+
* based on the condition appropriate for light or dark mode.
|
|
91
|
+
* @returns {{import('./types'}.ShadeMapping[]>} An array of objects, where each object contains key, value, and mode
|
|
92
|
+
* properties corresponding to a CSS custom property definition.
|
|
93
|
+
*/
|
|
94
|
+
function createShadeMappings(variant, mode, valueCondition) {
|
|
95
|
+
return shades.map((shade) => ({
|
|
96
|
+
key: `--on-${variant}-${shade}`,
|
|
97
|
+
value: valueCondition(shade),
|
|
98
|
+
mode
|
|
99
|
+
}))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Generates contrast colors for light and dark modes based on a given palette. Each color variant in the
|
|
104
|
+
* palette is mapped to either a light or dark contrast color depending on the shade's value.
|
|
105
|
+
*
|
|
106
|
+
* @param {string} [light='#ffffff'] - The default light color used when the shade is >= 500 in light mode or <= 500 in dark mode.
|
|
107
|
+
* @param {string} [dark='#000000'] - The default dark color used when the shade is < 500 in light mode or > 500 in dark mode.
|
|
108
|
+
* @param {Array<string>} [palette=defaultPalette] - An array of color variant names to generate contrast colors for.
|
|
109
|
+
* @returns {Array<Object>} An array containing contrast color rules organized by light and dark modes for each variant in the palette.
|
|
110
|
+
*/
|
|
111
|
+
export function contrastColors(light = '#ffffff', dark = '#000000', palette = defaultPalette) {
|
|
112
|
+
const colors = palette
|
|
113
|
+
.flatMap((variant) => [
|
|
114
|
+
createShadeMappings(variant, 'light', (shade) => (shade < 500 ? dark : light)),
|
|
115
|
+
createShadeMappings(variant, 'dark', (shade) => (shade > 500 ? dark : light))
|
|
116
|
+
])
|
|
117
|
+
.reduce((acc, item) => [...acc, ...item], [])
|
|
118
|
+
return colors
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Generates color rules for a specific theme variant, for both light and dark modes.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} variant - The name of the variant to generate rules for.
|
|
124
|
+
* @param {Object} colors - The object containing color definitions.
|
|
125
|
+
* @param {Object} mapping - An object that maps variant names to color property names.
|
|
126
|
+
* @returns {import('./types').ShadeMappings} An array containing the color rules for both light and dark modes.
|
|
127
|
+
*/
|
|
128
|
+
function generateColorRules(variant, colors, mapping) {
|
|
129
|
+
return shades.flatMap((shade, index) => [
|
|
130
|
+
{
|
|
131
|
+
key: `--${variant}-${shade}`,
|
|
132
|
+
value: colors[mapping[variant]][shade],
|
|
133
|
+
mode: 'light'
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
key: `--${variant}-${shade}`,
|
|
137
|
+
value: colors[mapping[variant]][shades[shades.length - index - 1]],
|
|
138
|
+
mode: 'dark'
|
|
139
|
+
}
|
|
140
|
+
])
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Filters the rules for a specific mode and transforms them into an object mapping
|
|
145
|
+
* CSS variable names to their values.
|
|
146
|
+
*
|
|
147
|
+
* @param {Array<Object>} rules - The array of rules to filter and transform.
|
|
148
|
+
* @param {'light' | 'dark'} mode - The mode to filter by.
|
|
149
|
+
* @returns {Object} An object containing the rules specific to the provided mode.
|
|
150
|
+
*/
|
|
151
|
+
function filterRulesByMode(rules, mode) {
|
|
152
|
+
return rules
|
|
153
|
+
.filter((rule) => rule.mode === mode)
|
|
154
|
+
.reduce((acc, { key, value }) => ({ ...acc, [key]: value }), {})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Creates a theme variant object with a given mode, a collection of color rules, and additional colors.
|
|
159
|
+
*
|
|
160
|
+
* @param {string} name - The base name for the theme variant.
|
|
161
|
+
* @param {'light' | 'dark'} mode - The mode of the theme variant.
|
|
162
|
+
* @param {Object} colors - The object containing color rules for the theme.
|
|
163
|
+
* @param {Object} extraColors - Any additional color properties for the theme.
|
|
164
|
+
* @returns {Array} An array where the first element is the theme's name and the second element
|
|
165
|
+
* is an object containing all color rules and extra properties for the theme variant.
|
|
166
|
+
*/
|
|
167
|
+
function createThemeVariant(name, mode, colors, extraColors) {
|
|
168
|
+
return [
|
|
169
|
+
`${name}-mode-${mode}`,
|
|
170
|
+
{
|
|
171
|
+
...colors,
|
|
172
|
+
...extraColors,
|
|
173
|
+
'--plot-background': 'var(--neutral-200)'
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Constructs and returns the light and dark theme variants based on provided color mapping and color definitions.
|
|
180
|
+
*
|
|
181
|
+
* @param {string} name - The base name for the theme, defaults to 'rokkit' if not provided.
|
|
182
|
+
* @param {Object} [mapping=defaultThemeMapping] - An object mapping variant names to color property names.
|
|
183
|
+
* @param {Object} [colors=defaultColors] - The object containing default color definitions.
|
|
184
|
+
* @returns {Array<Array>} An array containing two arrays, one for the light theme variant and another for the dark theme.
|
|
185
|
+
*/
|
|
186
|
+
export function themeRules(name = 'rokkit', mapping = defaultThemeMapping, colors = defaultColors) {
|
|
187
|
+
mapping = { ...defaultThemeMapping, ...mapping }
|
|
188
|
+
const variants = Object.keys(mapping)
|
|
189
|
+
|
|
190
|
+
const rules = variants.reduce(
|
|
191
|
+
(acc, variant) => [
|
|
192
|
+
...acc,
|
|
193
|
+
...generateColorRules(variant, { ...defaultColors, ...colors }, mapping)
|
|
194
|
+
],
|
|
195
|
+
[]
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
const lightRules = filterRulesByMode(rules, 'light')
|
|
199
|
+
const darkRules = filterRulesByMode(rules, 'dark')
|
|
200
|
+
|
|
201
|
+
const lightTheme = createThemeVariant(name, 'light', lightRules, syntaxColors['one-dark'].light)
|
|
202
|
+
const darkTheme = createThemeVariant(name, 'dark', darkRules, syntaxColors['one-dark'].dark)
|
|
203
|
+
|
|
204
|
+
return [lightTheme, darkTheme]
|
|
205
|
+
}
|
package/src/ticks.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates an array of tick marks for a range of values.
|
|
3
|
+
*
|
|
4
|
+
* @param {number} lowerBound - The lower bound of the range.
|
|
5
|
+
* @param {number} upperBound - The upper bound of the range.
|
|
6
|
+
* @param {number} [minorTickStep=upperBound-lowerBound] - The step size for minor ticks.
|
|
7
|
+
* @param {number} [majorTickStep=1] - The step size for major ticks.
|
|
8
|
+
* @returns {import('./types').TickMark[]>} An array of tick mark objects.
|
|
9
|
+
*/
|
|
10
|
+
export function generateTicks(
|
|
11
|
+
lowerBound,
|
|
12
|
+
upperBound,
|
|
13
|
+
minorTickStep = upperBound - lowerBound,
|
|
14
|
+
majorTickStep = 1
|
|
15
|
+
) {
|
|
16
|
+
const length = 1 + Math.ceil((upperBound - lowerBound) / minorTickStep)
|
|
17
|
+
return Array.from({ length }, (_, i) => {
|
|
18
|
+
const value = i === length - 1 ? upperBound : lowerBound + minorTickStep * i
|
|
19
|
+
const major = i === 0 || i === length - 1 || i % majorTickStep === 0
|
|
20
|
+
return {
|
|
21
|
+
value,
|
|
22
|
+
label: major ? value : '',
|
|
23
|
+
major
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
}
|
package/src/types.js
CHANGED
package/src/utils.js
CHANGED
|
@@ -83,3 +83,21 @@ export function scaledPath(size, x) {
|
|
|
83
83
|
if (Array.isArray(x)) return x.map((v) => scaledPath(size, v)).join(' ')
|
|
84
84
|
return typeof x === 'number' ? x * size : x
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Gets a key string from path
|
|
89
|
+
* @param {string[]} path
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
export function getKeyFromPath(path) {
|
|
93
|
+
return path.join('-')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets a path array from key string
|
|
98
|
+
* @param {string} key
|
|
99
|
+
* @returns {string[]}
|
|
100
|
+
*/
|
|
101
|
+
export function getPathFromKey(key) {
|
|
102
|
+
return key.split('-').map(Number)
|
|
103
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Jerry Thomas
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|