@rokkit/core 1.0.0-next.16 → 1.0.0-next.160
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 +121 -1
- package/package.json +31 -39
- package/src/calendar.js +44 -0
- package/src/colors/extra.json +16 -0
- package/src/colors/index.ts +24 -0
- package/src/colors/syntax.json +42 -0
- package/src/colors/tailwind.json +275 -0
- package/src/connector.js +34 -0
- package/src/constants.js +165 -107
- package/src/events.js +32 -0
- package/src/field-mapper.js +147 -0
- package/src/index.js +19 -27
- package/src/key-event-map.js +35 -0
- package/src/mapped-items.js +22 -0
- package/src/mapping.js +21 -0
- package/src/nested.js +28 -0
- package/src/string.js +97 -0
- package/src/theme.ts +208 -0
- package/src/ticks.js +26 -0
- package/src/types.js +160 -0
- package/src/utils.js +272 -0
- package/src/vite/icon-collections.js +73 -0
- package/src/vite/index.js +1 -0
- package/LICENSE +0 -21
- package/src/Accordion.svelte +0 -80
- package/src/Alerts.svelte +0 -39
- package/src/DropDown.svelte +0 -82
- package/src/DropSearch.svelte +0 -67
- package/src/EditableTabs.svelte +0 -31
- package/src/Icon.svelte +0 -15
- package/src/List-Discard.svelte +0 -48
- package/src/List.svelte +0 -65
- package/src/ListActions.svelte +0 -35
- package/src/NavTabs.svelte +0 -0
- package/src/NestedList.svelte +0 -77
- package/src/Overlay.svelte +0 -4
- package/src/PageNavigator.svelte +0 -94
- package/src/ResponsiveGrid.svelte +0 -73
- package/src/Scrollable.svelte +0 -8
- package/src/Searchable.svelte +0 -19
- package/src/Sidebar.svelte +0 -5
- package/src/Slider.svelte +0 -17
- package/src/SpinList.svelte +0 -48
- package/src/SplitPane.svelte +0 -109
- package/src/SplitView.svelte +0 -44
- package/src/Splitter.svelte +0 -95
- package/src/TabItem.svelte +0 -27
- package/src/TabItems.svelte +0 -34
- package/src/Tabs.svelte +0 -49
- package/src/Tree.svelte +0 -45
- package/src/actions/dismissable.js +0 -24
- package/src/actions/fillable.js +0 -114
- package/src/actions/hierarchy.js +0 -180
- package/src/actions/index.js +0 -7
- package/src/actions/navigable.js +0 -43
- package/src/actions/navigator.js +0 -179
- package/src/actions/pannable.js +0 -50
- package/src/actions/swipeable.js +0 -56
- package/src/actions/themeable.js +0 -23
- package/src/items/Collapsible.svelte +0 -51
- package/src/items/Connector.svelte +0 -26
- package/src/items/Link.svelte +0 -18
- package/src/items/Node.svelte +0 -52
- package/src/items/Pill.svelte +0 -33
- package/src/items/Separator.svelte +0 -1
- package/src/items/Summary.svelte +0 -27
- package/src/items/Text.svelte +0 -21
- package/src/items/index.js +0 -8
- package/src/list.js +0 -14
- package/src/mocks/Custom.svelte +0 -7
- package/src/mocks/index.js +0 -10
- package/src/stores/alerts.js +0 -3
- package/src/stores/index.js +0 -6
- package/src/stores/persist.js +0 -63
- package/src/stores/theme.js +0 -34
package/src/constants.js
CHANGED
|
@@ -1,102 +1,149 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { defaultColors, syntaxColors, shades, defaultPalette } from './colors/index'
|
|
2
|
+
export const DATA_IMAGE_REGEX = /^data:image\/(jpeg|png|gif|bmp|webp|svg\+xml)/i
|
|
3
|
+
|
|
4
|
+
// ─── Snippet names ────────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export const ITEM_SNIPPET = 'itemContent'
|
|
7
|
+
export const GROUP_SNIPPET = 'groupContent'
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Use BASE_FIELDS from @rokkit/core instead.
|
|
10
|
+
* Retained for legacy ListController/FieldMapper/Proxy consumers (Toolbar, Table).
|
|
11
|
+
* Will be removed when those components migrate to Wrapper+Navigator.
|
|
12
|
+
* @type {import('./types).FieldMapping} Fields
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_FIELDS = {
|
|
15
|
+
id: 'id',
|
|
16
|
+
href: 'href',
|
|
17
|
+
icon: 'icon',
|
|
18
|
+
text: 'text',
|
|
19
|
+
value: 'value',
|
|
20
|
+
keywords: 'keywords',
|
|
21
|
+
children: 'children',
|
|
22
|
+
iconPrefix: null,
|
|
23
|
+
image: 'image',
|
|
24
|
+
summary: 'summary',
|
|
25
|
+
notes: 'notes',
|
|
26
|
+
props: 'props',
|
|
27
|
+
target: 'target',
|
|
28
|
+
state: 'state',
|
|
29
|
+
level: 'level',
|
|
30
|
+
parent: 'parent',
|
|
31
|
+
currency: 'currency',
|
|
32
|
+
label: 'label',
|
|
33
|
+
component: 'component', // to be deprecated in favour of snippet
|
|
34
|
+
snippet: 'snippet',
|
|
35
|
+
disabled: 'disabled',
|
|
36
|
+
/* flag fields */
|
|
37
|
+
deleted: '_deleted',
|
|
38
|
+
expanded: '_expanded',
|
|
39
|
+
selected: '_selected'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── BASE_FIELDS ─────────────────────────────────────────────────────────────
|
|
43
|
+
// Canonical field mapping for ProxyItem and all Wrapper+Navigator components.
|
|
44
|
+
// Semantic keys map to common raw data keys for backward compatibility.
|
|
45
|
+
|
|
46
|
+
export const BASE_FIELDS = {
|
|
47
|
+
// Identity
|
|
48
|
+
id: 'id',
|
|
49
|
+
value: 'value',
|
|
50
|
+
// Display
|
|
51
|
+
label: 'label',
|
|
52
|
+
icon: 'icon',
|
|
53
|
+
avatar: 'image',
|
|
54
|
+
subtext: 'description',
|
|
55
|
+
tooltip: 'title',
|
|
56
|
+
badge: 'badge',
|
|
57
|
+
shortcut: 'shortcut',
|
|
58
|
+
// Structure
|
|
59
|
+
children: 'children',
|
|
60
|
+
type: 'type',
|
|
61
|
+
snippet: 'snippet',
|
|
62
|
+
href: 'href',
|
|
63
|
+
hrefTarget: 'target',
|
|
64
|
+
// State
|
|
65
|
+
disabled: 'disabled',
|
|
66
|
+
expanded: 'expanded',
|
|
67
|
+
selected: 'selected'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const DEFAULT_ICONS = [
|
|
2
71
|
'accordion-opened',
|
|
3
72
|
'accordion-closed',
|
|
4
73
|
'action-remove',
|
|
74
|
+
'action-cancel',
|
|
75
|
+
'action-retry',
|
|
5
76
|
'action-add',
|
|
6
77
|
'action-clear',
|
|
7
78
|
'action-search',
|
|
8
79
|
'action-close',
|
|
9
|
-
'action-
|
|
80
|
+
'action-copy',
|
|
81
|
+
'action-copysuccess',
|
|
82
|
+
'action-check',
|
|
83
|
+
'action-pin',
|
|
84
|
+
'action-save',
|
|
85
|
+
'action-unpin',
|
|
10
86
|
'node-opened',
|
|
11
87
|
'node-closed',
|
|
88
|
+
'folder-opened',
|
|
89
|
+
'folder-closed',
|
|
12
90
|
'selector-opened',
|
|
13
91
|
'selector-closed',
|
|
92
|
+
'menu-opened',
|
|
93
|
+
'menu-closed',
|
|
14
94
|
'checkbox-checked',
|
|
15
95
|
'checkbox-unchecked',
|
|
16
96
|
'checkbox-unknown',
|
|
17
97
|
'rating-filled',
|
|
18
98
|
'rating-empty',
|
|
99
|
+
'rating-half',
|
|
19
100
|
'radio-off',
|
|
20
101
|
'radio-on',
|
|
21
102
|
'mode-dark',
|
|
22
103
|
'mode-light',
|
|
104
|
+
'mode-system',
|
|
23
105
|
'navigate-left',
|
|
24
106
|
'navigate-right',
|
|
25
107
|
'navigate-up',
|
|
26
|
-
'navigate-down'
|
|
108
|
+
'navigate-down',
|
|
109
|
+
'palette-hex',
|
|
110
|
+
'palette-presets',
|
|
111
|
+
'state-error',
|
|
112
|
+
'state-warning',
|
|
113
|
+
'state-success',
|
|
114
|
+
'state-info',
|
|
115
|
+
'state-unknown',
|
|
116
|
+
'badge-fail',
|
|
117
|
+
'badge-warn',
|
|
118
|
+
'badge-pass',
|
|
119
|
+
'badge-unknown',
|
|
120
|
+
'sort-none',
|
|
121
|
+
'sort-ascending',
|
|
122
|
+
'sort-descending',
|
|
123
|
+
'validity-failed',
|
|
124
|
+
'validity-passed',
|
|
125
|
+
'validity-unknown',
|
|
126
|
+
'validity-warning',
|
|
127
|
+
'alert-clear',
|
|
128
|
+
'alert-unread',
|
|
129
|
+
'align-horizontal-left',
|
|
130
|
+
'align-horizontal-right',
|
|
131
|
+
'align-horizontal-center',
|
|
132
|
+
'align-vertical-top',
|
|
133
|
+
'align-vertical-bottom',
|
|
134
|
+
'align-vertical-middle',
|
|
135
|
+
'view-code',
|
|
136
|
+
'view-chart'
|
|
27
137
|
]
|
|
28
138
|
|
|
29
|
-
|
|
30
|
-
// 'accordion-opened',
|
|
31
|
-
// 'accordion-closed',
|
|
32
|
-
// 'action-remove',
|
|
33
|
-
// 'action-add',
|
|
34
|
-
// 'action-clear',
|
|
35
|
-
// 'action-search',
|
|
36
|
-
// 'action-close',
|
|
37
|
-
// 'node-opened',
|
|
38
|
-
// 'node-closed',
|
|
39
|
-
// 'checkbox-checked',
|
|
40
|
-
// 'checkbox-unchecked',
|
|
41
|
-
// 'checkbox-unknown',
|
|
42
|
-
// 'rating-filled',
|
|
43
|
-
// 'rating-empty',
|
|
44
|
-
// 'rating-half',
|
|
45
|
-
// 'radio-off',
|
|
46
|
-
// 'radio-on',
|
|
47
|
-
// 'folder-closed',
|
|
48
|
-
// 'folder-opened',
|
|
49
|
-
// 'navigate-up',
|
|
50
|
-
// 'navigate-down',
|
|
51
|
-
// 'navigate-left',
|
|
52
|
-
// 'navigate-right',
|
|
53
|
-
// 'selector-closed',
|
|
54
|
-
// 'selector-opened',
|
|
55
|
-
// 'mode-dark',
|
|
56
|
-
// 'mode-light'
|
|
57
|
-
// ]
|
|
58
|
-
|
|
59
|
-
export const defaultOptions = {
|
|
139
|
+
export const DEFAULT_OPTIONS = {
|
|
60
140
|
id: 'id',
|
|
61
141
|
label: 'label',
|
|
62
142
|
value: 'value',
|
|
63
143
|
checked: 'checked'
|
|
64
144
|
}
|
|
65
145
|
|
|
66
|
-
|
|
67
|
-
* Structure to map custom fields for rendering
|
|
68
|
-
*
|
|
69
|
-
* @typedef FieldMapping
|
|
70
|
-
* @property {string} [id='id'] - Unique id for the item
|
|
71
|
-
* @property {string} [text='text'] - Attribute to identify the text to render
|
|
72
|
-
* @property {string} [url='url'] - Attribute to identify a URL
|
|
73
|
-
* @property {string} [icon='icon'] - Attribute to identify an icon class to render
|
|
74
|
-
* @property {string} [image='image'] - Attribute to identify an image to render
|
|
75
|
-
* @property {string} [children='children'] - Attribute to identify children of the current item
|
|
76
|
-
* @property {string} [summary='summary']
|
|
77
|
-
* @property {string} [notes='notes']
|
|
78
|
-
* @property {string} [props='props']
|
|
79
|
-
* @property {string} [isOpen='_open'] - Attribute to identify if the current item is open
|
|
80
|
-
* @property {string} [isDeleted='_deleted'] - Attribute to identify if the current item is deleted
|
|
81
|
-
* @property {FieldMapping} [fields] - Field mapping to be used on children in the next level
|
|
82
|
-
*/
|
|
83
|
-
export const defaultFields = {
|
|
84
|
-
id: 'id',
|
|
85
|
-
url: 'url',
|
|
86
|
-
text: 'text',
|
|
87
|
-
children: 'data',
|
|
88
|
-
icon: 'icon',
|
|
89
|
-
image: 'image',
|
|
90
|
-
component: 'component',
|
|
91
|
-
summary: 'summary',
|
|
92
|
-
notes: 'notes',
|
|
93
|
-
props: 'props',
|
|
94
|
-
target: 'target',
|
|
95
|
-
isOpen: '_open',
|
|
96
|
-
isDeleted: '_deleted'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export const defaultKeyMap = {
|
|
146
|
+
export const DEFAULT_KEYMAP = {
|
|
100
147
|
ArrowRight: 'open',
|
|
101
148
|
ArrowLeft: 'close',
|
|
102
149
|
ArrowDown: 'down',
|
|
@@ -105,45 +152,56 @@ export const defaultKeyMap = {
|
|
|
105
152
|
Escape: 'deselect'
|
|
106
153
|
}
|
|
107
154
|
|
|
155
|
+
export const DEFAULT_THEME_MAPPING = {
|
|
156
|
+
surface: 'slate',
|
|
157
|
+
primary: 'orange',
|
|
158
|
+
secondary: 'pink',
|
|
159
|
+
accent: 'sky',
|
|
160
|
+
success: 'green',
|
|
161
|
+
warning: 'yellow',
|
|
162
|
+
danger: 'red',
|
|
163
|
+
error: 'red',
|
|
164
|
+
info: 'cyan'
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const TONE_MAP = {
|
|
168
|
+
z0: 50,
|
|
169
|
+
z1: 100,
|
|
170
|
+
z2: 200,
|
|
171
|
+
z3: 300,
|
|
172
|
+
z4: 400,
|
|
173
|
+
z5: 500,
|
|
174
|
+
z6: 600,
|
|
175
|
+
z7: 700,
|
|
176
|
+
z8: 800,
|
|
177
|
+
z9: 900,
|
|
178
|
+
z10: 950
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Splits an icon name into its group and key components.
|
|
182
|
+
* @param {string} name - The icon name to split.
|
|
183
|
+
* @returns {{ group: string, key: string, value: string }} An object containing the group, key, and value of the icon name.
|
|
184
|
+
*/
|
|
185
|
+
function splitIconName(name) {
|
|
186
|
+
const parts = name.split('-')
|
|
187
|
+
const group = parts.slice(0, parts.length - 1).join('-')
|
|
188
|
+
return { group, key: parts[parts.length - 1], value: name }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Generate a state icon mapping from a list of icon names
|
|
193
|
+
*
|
|
194
|
+
* @param {string[]} icons
|
|
195
|
+
* @returns {import('./types').StateIcons}
|
|
196
|
+
*/
|
|
108
197
|
export function stateIconsFromNames(icons) {
|
|
109
|
-
return icons
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{}
|
|
117
|
-
)
|
|
198
|
+
return icons.map(splitIconName).reduce(
|
|
199
|
+
(acc, { group, key, value }) => ({
|
|
200
|
+
...acc,
|
|
201
|
+
[group]: { ...acc[group], [key]: value }
|
|
202
|
+
}),
|
|
203
|
+
{}
|
|
204
|
+
)
|
|
118
205
|
}
|
|
119
206
|
|
|
120
|
-
export const
|
|
121
|
-
// export const defaultStateIcons = {
|
|
122
|
-
// accordion: {
|
|
123
|
-
// opened: 'accordion-opened',
|
|
124
|
-
// closed: 'accordion-closed'
|
|
125
|
-
// },
|
|
126
|
-
// item: {
|
|
127
|
-
// remove: 'item-remove',
|
|
128
|
-
// add: 'item-add',
|
|
129
|
-
// clear: 'item-clear',
|
|
130
|
-
// search: 'item-search'
|
|
131
|
-
// },
|
|
132
|
-
// node: {
|
|
133
|
-
// opened: 'node-opened',
|
|
134
|
-
// closed: 'node-closed'
|
|
135
|
-
// },
|
|
136
|
-
// list: {
|
|
137
|
-
// selector: 'list-selector'
|
|
138
|
-
// },
|
|
139
|
-
// checkbox: {
|
|
140
|
-
// checked: 'checkbox-checked',
|
|
141
|
-
// unchecked: 'checkbox-unchecked',
|
|
142
|
-
// unknown: 'checkbox-unknown'
|
|
143
|
-
// },
|
|
144
|
-
// rating: { filled: 'rating-filled', empty: 'rating-empty' },
|
|
145
|
-
// radio: {
|
|
146
|
-
// off: 'radio-off',
|
|
147
|
-
// on: 'radio-on'
|
|
148
|
-
// }
|
|
149
|
-
// }
|
|
207
|
+
export const DEFAULT_STATE_ICONS = stateIconsFromNames(DEFAULT_ICONS)
|
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
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { isNil, has, omit } from 'ramda'
|
|
2
|
+
import { DEFAULT_FIELDS } from './constants.js'
|
|
3
|
+
import { isObject } from './utils.js'
|
|
4
|
+
|
|
5
|
+
export class FieldMapper {
|
|
6
|
+
#fields = { ...DEFAULT_FIELDS }
|
|
7
|
+
#childMapper = null
|
|
8
|
+
|
|
9
|
+
constructor(fields = DEFAULT_FIELDS) {
|
|
10
|
+
this.#updateFields(fields)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#updateFields(fields) {
|
|
14
|
+
Object.keys(fields).forEach((key) => {
|
|
15
|
+
this.#fields[key] = fields[key]
|
|
16
|
+
})
|
|
17
|
+
this.hasIcon = has(this.#fields.icon)
|
|
18
|
+
this.hasImage = has(this.#fields.image)
|
|
19
|
+
this.hasValue = has(this.#fields.value)
|
|
20
|
+
this.hasLabel = has(this.#fields.label)
|
|
21
|
+
this.hasComponent = has(this.#fields.component)
|
|
22
|
+
this.hasCurrency = has(this.#fields.currency)
|
|
23
|
+
this.withPrefix = (x) => [this.#fields.iconPrefix, x].join('-').replace(/^-+/g, '')
|
|
24
|
+
this.excludeFlags = omit([
|
|
25
|
+
this.#fields.isDeleted,
|
|
26
|
+
this.#fields.isHidden,
|
|
27
|
+
this.#fields.isSelected,
|
|
28
|
+
this.#fields.isFiltered,
|
|
29
|
+
this.#fields.isOpen
|
|
30
|
+
])
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getChildMapper() {
|
|
34
|
+
if (!this.#childMapper) {
|
|
35
|
+
this.#childMapper = new FieldMapper(this.fields.fields ?? this.fields)
|
|
36
|
+
}
|
|
37
|
+
return this.#childMapper
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
prop(fieldName, value) {
|
|
43
|
+
if (isNil(value)) return null
|
|
44
|
+
|
|
45
|
+
if (typeof value === 'object') {
|
|
46
|
+
return value[this.fields[fieldName]]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return fieldName === 'label' ? value : null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Gets a mapped attribute from the original item
|
|
54
|
+
*
|
|
55
|
+
* @param {string} fieldName - Name of the field to get
|
|
56
|
+
* @returns {any|null} - The attribute value or null if not found
|
|
57
|
+
*/
|
|
58
|
+
get(fieldName, value, defaultValue = null) {
|
|
59
|
+
return this.prop(fieldName, value) ?? defaultValue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get fields() {
|
|
63
|
+
return this.#fields
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
set fields(fields) {
|
|
67
|
+
this.#updateFields(fields)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getIcon(value) {
|
|
71
|
+
if (!this.hasIcon(value)) return null
|
|
72
|
+
const icon = value[this.fields.icon]
|
|
73
|
+
if (isObject(icon)) return this.withPrefix(icon[value[this.fields.state]])
|
|
74
|
+
return this.withPrefix(icon)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getValue(value) {
|
|
78
|
+
if (this.hasValue(value)) {
|
|
79
|
+
return value[this.fields.value]
|
|
80
|
+
}
|
|
81
|
+
return value
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getFormattedText(value, formatter) {
|
|
85
|
+
const text = this.get('label', value)
|
|
86
|
+
|
|
87
|
+
if (isNil(text)) return ''
|
|
88
|
+
|
|
89
|
+
if (typeof formatter !== 'function') return text.toString()
|
|
90
|
+
|
|
91
|
+
if (this.hasCurrency(value)) {
|
|
92
|
+
return formatter(text, this.get('currency', value))
|
|
93
|
+
}
|
|
94
|
+
return formatter(text)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
hasChildren(item) {
|
|
98
|
+
return (
|
|
99
|
+
!isNil(item) &&
|
|
100
|
+
has(this.fields.children, item) &&
|
|
101
|
+
Array.isArray(item[this.fields.children]) &&
|
|
102
|
+
item[this.fields.children].length > 0
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isNested(items) {
|
|
107
|
+
return Array.isArray(items) && items.some((item) => this.hasChildren(item))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getChildren(item) {
|
|
111
|
+
return this.hasChildren(item) ? item[this.fields.children] : []
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Finds children by an index path
|
|
116
|
+
*
|
|
117
|
+
* @param {Array<Object>} items
|
|
118
|
+
* @param {Array<number>} path
|
|
119
|
+
* @returns {Array<Object>}
|
|
120
|
+
*/
|
|
121
|
+
getChildrenByPath(items, path = []) {
|
|
122
|
+
const result = path.reduce(
|
|
123
|
+
(children, index) => children?.[index]?.[this.fields.children],
|
|
124
|
+
items
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if (result === undefined) throw new Error('Invalid path')
|
|
128
|
+
return result
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Finds an item by an index path
|
|
133
|
+
*
|
|
134
|
+
* @param {Array<Object>} items
|
|
135
|
+
* @param {Array<number>} path
|
|
136
|
+
* @returns {Object|null}
|
|
137
|
+
*/
|
|
138
|
+
getItemByPath(items, path = []) {
|
|
139
|
+
const result = path.reduce(
|
|
140
|
+
(item, index, i) => (i === 0 ? items?.[index] : item?.[this.fields.children]?.[index]),
|
|
141
|
+
/* skipcq: JS-W1042 default undefined is needed */ undefined
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if (result === undefined) throw new Error('Invalid path')
|
|
145
|
+
return result
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
export * from './
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
//
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export {
|
|
18
|
-
export {
|
|
19
|
-
|
|
20
|
-
export { default as Sidebar } from './Sidebar.svelte'
|
|
21
|
-
export { default as SplitPane } from './SplitPane.svelte'
|
|
22
|
-
export { default as Splitter } from './Splitter.svelte'
|
|
23
|
-
export { default as SplitView } from './SplitView.svelte'
|
|
24
|
-
export { default as Overlay } from './Overlay.svelte'
|
|
25
|
-
|
|
26
|
-
export { default as PageNavigator } from './PageNavigator.svelte'
|
|
27
|
-
export { default as ResponsiveGrid } from './ResponsiveGrid.svelte'
|
|
1
|
+
// skipcq: JS-E1004 - Needed for exposing JS Doc types
|
|
2
|
+
export * from './types.js'
|
|
3
|
+
// skipcq: JS-E1004 - Needed for exposing all constants
|
|
4
|
+
export * from './constants.js'
|
|
5
|
+
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
6
|
+
export * from './utils.js'
|
|
7
|
+
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
8
|
+
export * from './nested.js'
|
|
9
|
+
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
10
|
+
export * from './string.js'
|
|
11
|
+
// skipcq: JS-E1004 - Needed for exposing all functions
|
|
12
|
+
export * from './theme.js'
|
|
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'
|
|
19
|
+
export { getNestedFields } from './mapping.js'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { find, toPairs } from 'ramda'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Class to manage key event mappings.
|
|
5
|
+
*/
|
|
6
|
+
export class KeyEventMap {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.mapping = {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Add a new key mapping.
|
|
13
|
+
* @param {string} eventName - The event name.
|
|
14
|
+
* @param {Array<string>|RegExp} keys - The keys to match.
|
|
15
|
+
*/
|
|
16
|
+
add(eventName, keys) {
|
|
17
|
+
if (!Array.isArray(keys) && !(keys instanceof RegExp)) {
|
|
18
|
+
throw new Error('Keys must be an array or a regular expression')
|
|
19
|
+
}
|
|
20
|
+
this.mapping[eventName] = keys
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the event name for a given key.
|
|
25
|
+
* @param {string} key - The key to match.
|
|
26
|
+
* @returns {string|null} - The event name or null if no match is found.
|
|
27
|
+
*/
|
|
28
|
+
getEventForKey(key) {
|
|
29
|
+
const matchEvent = ([_, keys]) =>
|
|
30
|
+
(Array.isArray(keys) && keys.includes(key)) || (keys instanceof RegExp && keys.test(key))
|
|
31
|
+
|
|
32
|
+
const event = find(matchEvent, toPairs(this.mapping))
|
|
33
|
+
return event ? event[0] : null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -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/mapping.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DEFAULT_FIELDS } from './constants.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gets the attribute from the node
|
|
5
|
+
* @param {*} node
|
|
6
|
+
* @param {string} attr
|
|
7
|
+
* @returns {*}
|
|
8
|
+
*/
|
|
9
|
+
export function getAttribute(node, attr) {
|
|
10
|
+
return typeof node === 'object' && node !== null && attr !== null ? node[attr] : null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fetches the fieldmapping for a child node
|
|
15
|
+
*
|
|
16
|
+
* @param {import('./types').FieldMapping} fields
|
|
17
|
+
* @returns {import('./types').FieldMapping}
|
|
18
|
+
*/
|
|
19
|
+
export function getNestedFields(fields) {
|
|
20
|
+
return { ...DEFAULT_FIELDS, ...(fields.fields ?? fields) }
|
|
21
|
+
}
|
package/src/nested.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { omit } from 'ramda'
|
|
2
|
+
import { DEFAULT_FIELDS } from './constants.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Flattens a nested list of items
|
|
6
|
+
*
|
|
7
|
+
* @param {Array} items
|
|
8
|
+
* @param {import('./types).FieldMapping} fields
|
|
9
|
+
* @param {number} level
|
|
10
|
+
* @returns {Array}
|
|
11
|
+
*/
|
|
12
|
+
export function flattenNestedList(items, fields = DEFAULT_FIELDS, level = 0) {
|
|
13
|
+
fields = { ...DEFAULT_FIELDS, ...fields }
|
|
14
|
+
let data = []
|
|
15
|
+
items.forEach((item) => {
|
|
16
|
+
const children = item[fields.children] ?? []
|
|
17
|
+
data = [
|
|
18
|
+
...data,
|
|
19
|
+
{
|
|
20
|
+
...omit([fields.children], item),
|
|
21
|
+
[fields.level]: level,
|
|
22
|
+
[fields.parent]: children.length > 0
|
|
23
|
+
},
|
|
24
|
+
...flattenNestedList(children, fields, level + 1)
|
|
25
|
+
]
|
|
26
|
+
})
|
|
27
|
+
return data
|
|
28
|
+
}
|