@rokkit/core 1.0.0-next.90 → 1.0.0-next.91
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/package.json +3 -3
- package/src/constants.js +12 -3
- package/src/formatter.js +47 -0
- package/src/parser.js +52 -2
- package/src/tabular.js +64 -0
- package/src/types.js +58 -3
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.91",
|
|
4
4
|
"description": "Core components, actions and stores for svelte apps.",
|
|
5
5
|
"author": "Jerry Thomas <me@jerrythomas.name>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"typescript": "^5.3.3",
|
|
23
23
|
"vite": "^5.1.4",
|
|
24
24
|
"vitest": "~1.3.1",
|
|
25
|
-
"shared-config": "1.0.0-next.
|
|
26
|
-
"validators": "1.0.0-next.
|
|
25
|
+
"shared-config": "1.0.0-next.91",
|
|
26
|
+
"validators": "1.0.0-next.91"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src/**/*.js",
|
package/src/constants.js
CHANGED
|
@@ -6,8 +6,8 @@ export { defaultColors, syntaxColors, shades, defaultPalette } from './colors'
|
|
|
6
6
|
export const defaultFields = {
|
|
7
7
|
id: 'id',
|
|
8
8
|
url: 'url',
|
|
9
|
-
value: 'value',
|
|
10
9
|
text: 'text',
|
|
10
|
+
value: 'value',
|
|
11
11
|
children: 'children',
|
|
12
12
|
icon: 'icon',
|
|
13
13
|
iconPrefix: null,
|
|
@@ -21,7 +21,8 @@ export const defaultFields = {
|
|
|
21
21
|
isOpen: '_open',
|
|
22
22
|
isDeleted: '_deleted',
|
|
23
23
|
level: 'level',
|
|
24
|
-
parent: 'parent'
|
|
24
|
+
parent: 'parent',
|
|
25
|
+
currency: 'currency'
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export const defaultIcons = [
|
|
@@ -41,6 +42,7 @@ export const defaultIcons = [
|
|
|
41
42
|
'checkbox-unknown',
|
|
42
43
|
'rating-filled',
|
|
43
44
|
'rating-empty',
|
|
45
|
+
'rating-half',
|
|
44
46
|
'radio-off',
|
|
45
47
|
'radio-on',
|
|
46
48
|
'mode-dark',
|
|
@@ -57,7 +59,14 @@ export const defaultIcons = [
|
|
|
57
59
|
'badge-fail',
|
|
58
60
|
'badge-warn',
|
|
59
61
|
'badge-pass',
|
|
60
|
-
'badge-unknown'
|
|
62
|
+
'badge-unknown',
|
|
63
|
+
'sort-none',
|
|
64
|
+
'sort-ascending',
|
|
65
|
+
'sort-descending',
|
|
66
|
+
'validity-failed',
|
|
67
|
+
'validity-passed',
|
|
68
|
+
'validity-unknown',
|
|
69
|
+
'validity-warning'
|
|
61
70
|
]
|
|
62
71
|
|
|
63
72
|
export const defaultOptions = {
|
package/src/formatter.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { identity } from 'ramda'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a formatter function that formats a value according to the specified type and optional locale settings.
|
|
5
|
+
* Supported types include 'default' (no formatting), 'integer', 'number', 'date', 'time', and 'currency'.
|
|
6
|
+
*
|
|
7
|
+
* The function is curried, which means it can be partially applied with some arguments and reused
|
|
8
|
+
* to format different values with the same settings.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} type - The type of the formatter to use (e.g., 'integer', 'number', 'date', 'time', 'currency').
|
|
11
|
+
* @param {string} [language='en-US'] - Optional IETF language tag used for locale-specific formatting.
|
|
12
|
+
* @param {string} [currency='USD'] - Optional currency code which is relevant when the type is 'currency'.
|
|
13
|
+
* @param {number} [decimalPlaces=2] - Optional number of decimal places to show with number and currency formatting.
|
|
14
|
+
* @param {number|Date} value - The value to format, it should be of a type corresponding to the formatter type.
|
|
15
|
+
* @returns {*} - The formatted value as a string or the original value if formatting is not applicable.
|
|
16
|
+
*/
|
|
17
|
+
export function createFormatter(type, language = 'en-US', decimalPlaces = 2, currency) {
|
|
18
|
+
const formatWithLocaleOptions = (options, val) => val.toLocaleString(language, options)
|
|
19
|
+
const formatCurrency = (val, currency = 'USD') =>
|
|
20
|
+
val.toLocaleString(language, {
|
|
21
|
+
style: 'currency',
|
|
22
|
+
currency,
|
|
23
|
+
minimumFractionDigits: decimalPlaces,
|
|
24
|
+
maximumFractionDigits: decimalPlaces
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const formatters = {
|
|
28
|
+
integer: (val) => formatWithLocaleOptions({ maximumFractionDigits: 0 }, val), // Integer without decimals
|
|
29
|
+
number: (val) =>
|
|
30
|
+
formatWithLocaleOptions(
|
|
31
|
+
{
|
|
32
|
+
minimumFractionDigits: decimalPlaces,
|
|
33
|
+
maximumFractionDigits: decimalPlaces
|
|
34
|
+
},
|
|
35
|
+
val
|
|
36
|
+
), // Number with fixed decimal places
|
|
37
|
+
date: (val) => val.toLocaleDateString(language), // Locale-specific date format
|
|
38
|
+
time: (val) => val.toLocaleTimeString(language), // Locale-specific time format
|
|
39
|
+
currency: currency ? (val) => formatCurrency(val, currency) : formatCurrency
|
|
40
|
+
// Currency with fixed decimal places and currency symbol
|
|
41
|
+
}
|
|
42
|
+
if (type in formatters) return formatters[type]
|
|
43
|
+
return identity
|
|
44
|
+
// return propOr(identity, type, formatters)(value) // Apply the formatter based on the type
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// export
|
package/src/parser.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constructs a regular expression pattern for matching search filter strings.
|
|
3
|
+
* The pattern captures "column", "operator", and "value" groups for filter expressions.
|
|
4
|
+
* Supported operators include common comparison and wildcard operators.
|
|
5
|
+
*
|
|
6
|
+
* Examples of valid expressions this regex can match:
|
|
7
|
+
* - "username:john_doe"
|
|
8
|
+
* - "age>30"
|
|
9
|
+
* - "status!=active"
|
|
10
|
+
* - "title~\"Product Manager\""
|
|
11
|
+
* - "completed!~*yes"
|
|
12
|
+
*
|
|
13
|
+
* The "column" group matches one or more word characters.
|
|
14
|
+
* The "operator" group matches one among the specified comparison or wildcard operators:
|
|
15
|
+
* :, >, <, >=, <=, =<, =>, =, !=, ~, ~*, !~, !~*.
|
|
16
|
+
* The "value" group matches either a double-quoted string or a single unquoted word
|
|
17
|
+
* that doesn't include whitespace or any of the operator characters.
|
|
18
|
+
*
|
|
19
|
+
* @returns {RegExp} - The regular expression pattern to identify search filter elements.
|
|
20
|
+
*/
|
|
1
21
|
export function getRegex() {
|
|
2
22
|
let column = '[\\w]+'
|
|
3
23
|
let operator = ':|>|<|>=|<=|=<|=>|=|!=|~|~\\*|!~|!~\\*'
|
|
@@ -8,6 +28,15 @@ export function getRegex() {
|
|
|
8
28
|
return new RegExp(pattern, 'gm')
|
|
9
29
|
}
|
|
10
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Parses a search string and extracts filters based on a predefined regular expression pattern.
|
|
33
|
+
* Each filter captures column, operator, and value components. Any remaining text that
|
|
34
|
+
* does not fit the pattern is considered a general search term.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} string - The search string to parse for filters.
|
|
37
|
+
* @returns {Object[]} - An array of filter objects each containing the column, operator, and value,
|
|
38
|
+
* plus an additional object for general search if there is remaining text.
|
|
39
|
+
*/
|
|
11
40
|
export function parseFilters(string) {
|
|
12
41
|
const results = []
|
|
13
42
|
const regex = getRegex()
|
|
@@ -38,15 +67,30 @@ export function parseFilters(string) {
|
|
|
38
67
|
return results
|
|
39
68
|
}
|
|
40
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Replaces various shorthand operators with their standardized equivalent for filtering.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} operator - The operator to be replaced.
|
|
74
|
+
* @returns {string} - The replaced operator string.
|
|
75
|
+
*/
|
|
41
76
|
function replaceOperators(operator) {
|
|
42
77
|
return operator.replace(':', '~*').replace('=>', '>=').replace('=<', '<=')
|
|
43
78
|
}
|
|
44
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Processes the filter value provided, converting it into a format suitable for filtering.
|
|
82
|
+
* If the operator includes a tilde (~), the value is converted to a RegExp.
|
|
83
|
+
*
|
|
84
|
+
* @param {string|number} value - The value to be processed. It could be a string needing quote removal or a number that needs parsing.
|
|
85
|
+
* @param {string} operator - The operator that determines the type of processing to be applied to the value.
|
|
86
|
+
* @returns {string|number|RegExp} - The processed value, which may be a RegExp if the operator involves pattern matching.
|
|
87
|
+
*/
|
|
45
88
|
function processValue(value, operator) {
|
|
46
|
-
//
|
|
89
|
+
// If the value can be parsed as an integer, do so. Otherwise, strip quotes if present.
|
|
47
90
|
|
|
48
91
|
value = !isNaN(parseInt(value)) ? parseInt(value) : removeQuotes(value)
|
|
49
|
-
|
|
92
|
+
// If the operator includes a tilde (~), treat the value as a regular expression,
|
|
93
|
+
// case-insensitive if '*' is present, sensitive otherwise.
|
|
50
94
|
if (operator.includes('~')) {
|
|
51
95
|
value = operator.includes('*') ? new RegExp(value, 'i') : new RegExp(value)
|
|
52
96
|
}
|
|
@@ -54,6 +98,12 @@ function processValue(value, operator) {
|
|
|
54
98
|
return value
|
|
55
99
|
}
|
|
56
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Removes double quotes from the start and end of a string.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} str - The input string from which the surrounding quotes should be removed.
|
|
105
|
+
* @returns {string} - The unquoted string.
|
|
106
|
+
*/
|
|
57
107
|
function removeQuotes(str) {
|
|
58
108
|
const quoteMatch = str.match(/^"([^"]+)"$/)
|
|
59
109
|
return quoteMatch ? quoteMatch[1] : str
|
package/src/tabular.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createFormatter } from './formatter'
|
|
2
|
+
|
|
3
|
+
export function tabular(data, columns, options) {
|
|
4
|
+
const { path, separator = '/', actions } = options ?? {}
|
|
5
|
+
|
|
6
|
+
let metadata = columns
|
|
7
|
+
if (!Array.isArray(columns) || columns.length === 0) metadata = deriveColumnMetadata(data)
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
data,
|
|
11
|
+
columns: metadata,
|
|
12
|
+
filter: () => {},
|
|
13
|
+
sort: () => {}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Derives column metadata from the data to be used in a tabular component.
|
|
19
|
+
*
|
|
20
|
+
* @param {Array} data - The data to derive column metadata from.
|
|
21
|
+
* @returns {Array<import('./types').ColumnMetadata>} - The derived column metadata.
|
|
22
|
+
*/
|
|
23
|
+
export function deriveColumnMetadata(dataArray) {
|
|
24
|
+
if (dataArray.length === 0) {
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const firstRow = dataArray[0]
|
|
29
|
+
const language = navigator.language || 'en-US' // Get the browser's language or default to 'en-US'
|
|
30
|
+
|
|
31
|
+
const columns = []
|
|
32
|
+
|
|
33
|
+
for (const key in firstRow) {
|
|
34
|
+
// if (Object.prototype.hasOwnProperty.call(firstRow, key)) {
|
|
35
|
+
const dataType = typeof firstRow[key]
|
|
36
|
+
const formatter = createFormatter(dataType, language)
|
|
37
|
+
const fields = { text: key }
|
|
38
|
+
|
|
39
|
+
if (key.endsWith('_currency')) {
|
|
40
|
+
const currencyColumn = key
|
|
41
|
+
const baseColumn = key.replace(/_currency$/, '')
|
|
42
|
+
|
|
43
|
+
// Find the existing column and update its currency attribute
|
|
44
|
+
const existingColumn = columns.find((column) => column.name === baseColumn)
|
|
45
|
+
existingColumn.dataType = 'currency'
|
|
46
|
+
existingColumn.formatter = createFormatter('currency', language, 2)
|
|
47
|
+
if (existingColumn) {
|
|
48
|
+
existingColumn.fields = {
|
|
49
|
+
...existingColumn.fields,
|
|
50
|
+
currency: currencyColumn
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
columns.push({
|
|
55
|
+
name: key,
|
|
56
|
+
dataType: dataType,
|
|
57
|
+
fields,
|
|
58
|
+
formatter
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return columns
|
|
64
|
+
}
|
package/src/types.js
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the sort order of the column.
|
|
3
|
+
*
|
|
4
|
+
* @typedef {'ascending'|'descending'|'none'} SortOptions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for the horizontal alignment of the column content.
|
|
9
|
+
*
|
|
10
|
+
* @typedef {'left'|'middle'|'right'} HorizontalAlignOptions
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for the action type of the column.
|
|
15
|
+
*
|
|
16
|
+
* @typedef {'select'|'edit'|'delete'} ActionTypes
|
|
17
|
+
*/
|
|
18
|
+
|
|
1
19
|
/**
|
|
2
20
|
* Structure to map custom fields for rendering. This is used to identofy the attributes for various purposes.
|
|
3
21
|
*
|
|
4
22
|
* @typedef FieldMapping
|
|
5
23
|
* @property {string} [id='id'] Unique id for the item
|
|
6
24
|
* @property {string} [text='text'] the text to render
|
|
25
|
+
* @property {string} [value='value'] the value associated with the item
|
|
7
26
|
* @property {string} [url='url'] a URL
|
|
8
27
|
* @property {string} [icon='icon'] icon to render
|
|
9
28
|
* @property {string} [image='image'] the image to render
|
|
10
29
|
* @property {string} [children='children'] children of the item
|
|
11
|
-
* @property {string} [summary='summary']
|
|
12
|
-
* @property {string} [notes='notes']
|
|
13
|
-
* @property {string} [props='props']
|
|
30
|
+
* @property {string} [summary='summary'] summary of the item
|
|
31
|
+
* @property {string} [notes='notes'] notes for the item
|
|
32
|
+
* @property {string} [props='props'] additional properties
|
|
14
33
|
* @property {string} [isOpen='_open'] item is open or closed
|
|
15
34
|
* @property {string} [level='level'] level of item
|
|
16
35
|
* @property {string} [parent='parent'] item is a parent
|
|
36
|
+
* @property {string} [currency='currency] column specifying currency to be used for the current value
|
|
17
37
|
* @property {string} [isDeleted='_deleted'] item is deleted
|
|
18
38
|
* @property {FieldMapping} [fields] Field mapping to be used on children in the next level
|
|
19
39
|
*/
|
|
@@ -22,3 +42,38 @@
|
|
|
22
42
|
* Component map to be used to render the item.
|
|
23
43
|
* @typedef {Object<string, import('svelte').SvelteComponent>} ComponentMap
|
|
24
44
|
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Column metadata for the table.
|
|
48
|
+
*
|
|
49
|
+
* @typedef {Object} ColumnMetadata
|
|
50
|
+
*
|
|
51
|
+
* @property {string} name - The name of the column.
|
|
52
|
+
* @property {string} dataType - The data type of the column (e.g., "string", "number", "date").
|
|
53
|
+
* @property {FieldMapping} [fields] - Additional attributes for the column.
|
|
54
|
+
* @property {number} [digits=0] - The number of digits for numeric values (defaults to 0).
|
|
55
|
+
* @property {Function} formatter - A function to format the column value.
|
|
56
|
+
* @property {boolean} [virtual] - Indicates if the column is virtual (true/false).
|
|
57
|
+
* @property {boolean} [sortable] - Indicates if the column is sortable (true/false).
|
|
58
|
+
* @property {SortOptions} [sortOrder] - The sort order of the column.
|
|
59
|
+
* @property {HorizontalAlignOptions} [align] - The alignment of the column content.
|
|
60
|
+
* @property {ActionTypes} [action] - Action attribute for action columns.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Track the state of a row in the table.
|
|
65
|
+
*
|
|
66
|
+
* @typedef {Object} RowState
|
|
67
|
+
* @property {boolean} visible - Indicates whether the node is visible (true/false).
|
|
68
|
+
* @property {string} [label] - The label of the hierarchy node.
|
|
69
|
+
* @property {boolean} is_parent - Indicates if this node is a parent (true/false).
|
|
70
|
+
* @property {boolean} is_collapsed - Indicates whether the node is collapsed (true/false).
|
|
71
|
+
* @property {number[]} levels - Array of hierarchy indices, including parent indices.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Track the state of all rows in the table.
|
|
76
|
+
*
|
|
77
|
+
* @typedef {Object} RowStateMap
|
|
78
|
+
* @property {RowState[]} rows - Flat list of hierarchy nodes.
|
|
79
|
+
*/
|