@rimelight/ui 0.0.19 → 0.0.21

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.
@@ -0,0 +1,321 @@
1
+ ---
2
+ interface HighlightGroup {
3
+ keys: string[]
4
+ color?: string
5
+ label?: string
6
+ }
7
+
8
+ interface Props {
9
+ highlightedKeys?: string[]
10
+ groups?: HighlightGroup[]
11
+ keyGap?: number
12
+ sectionGap?: number
13
+ keySize?: number
14
+ variant?: 'full' | '60'
15
+ os?: 'windows' | 'mac'
16
+ highlightColor?: string
17
+ backgroundColor?: string
18
+ }
19
+
20
+ const {
21
+ highlightedKeys = [],
22
+ groups = [],
23
+ keyGap = 8,
24
+ sectionGap = 40,
25
+ keySize = 40,
26
+ variant = 'full',
27
+ os = 'windows',
28
+ highlightColor = 'var(--ui-color-primary-500, #00c16a)',
29
+ backgroundColor = 'transparent'
30
+ } = Astro.props
31
+
32
+ interface Key {
33
+ label?: string
34
+ width: number
35
+ height?: number
36
+ code?: string
37
+ type?: 'spacer' | 'key'
38
+ }
39
+
40
+ const mainRows: Key[][] = [
41
+ [
42
+ { label: 'Esc', width: 1, code: 'Escape' },
43
+ { type: 'spacer', width: 1 },
44
+ { label: 'F1', width: 1 }, { label: 'F2', width: 1 }, { label: 'F3', width: 1 }, { label: 'F4', width: 1 },
45
+ { type: 'spacer', width: 0.5 },
46
+ { label: 'F5', width: 1 }, { label: 'F6', width: 1 }, { label: 'F7', width: 1 }, { label: 'F8', width: 1 },
47
+ { type: 'spacer', width: 0.5 },
48
+ { label: 'F9', width: 1 }, { label: 'F10', width: 1 }, { label: 'F11', width: 1 }, { label: 'F12', width: 1 },
49
+ ],
50
+ [
51
+ { label: '`', width: 1 }, { label: '1', width: 1, code: 'Digit1' }, { label: '2', width: 1, code: 'Digit2' }, { label: '3', width: 1, code: 'Digit3' },
52
+ { label: '4', width: 1, code: 'Digit4' }, { label: '5', width: 1, code: 'Digit5' }, { label: '6', width: 1, code: 'Digit6' }, { label: '7', width: 1, code: 'Digit7' },
53
+ { label: '8', width: 1, code: 'Digit8' }, { label: '9', width: 1, code: 'Digit9' }, { label: '0', width: 1, code: 'Digit0' }, { label: '-', width: 1, code: 'Minus' },
54
+ { label: '=', width: 1, code: 'Equal' }, { label: 'Bkspc', width: 2, code: 'Backspace' },
55
+ ],
56
+ [
57
+ { label: 'Tab', width: 1.5 }, { label: 'Q', width: 1 }, { label: 'W', width: 1 }, { label: 'E', width: 1 },
58
+ { label: 'R', width: 1 }, { label: 'T', width: 1 }, { label: 'Y', width: 1 }, { label: 'U', width: 1 },
59
+ { label: 'I', width: 1 }, { label: 'O', width: 1 }, { label: 'P', width: 1 }, { label: '[', width: 1 },
60
+ { label: ']', width: 1 }, { label: '\\', width: 1.5 },
61
+ ],
62
+ [
63
+ { label: 'Caps', width: 1.75, code: 'CapsLock' }, { label: 'A', width: 1 }, { label: 'S', width: 1 }, { label: 'D', width: 1 },
64
+ { label: 'F', width: 1 }, { label: 'G', width: 1 }, { label: 'H', width: 1 }, { label: 'J', width: 1 },
65
+ { label: 'K', width: 1 }, { label: 'L', width: 1 }, { label: ';', width: 1 }, { label: "'", width: 1 },
66
+ { label: 'Enter', width: 2.25, code: 'Enter' },
67
+ ],
68
+ [
69
+ { label: 'Shift', width: 2.5, code: 'ShiftLeft' }, { label: 'Z', width: 1 }, { label: 'X', width: 1 }, { label: 'C', width: 1 },
70
+ { label: 'V', width: 1 }, { label: 'B', width: 1 }, { label: 'N', width: 1 }, { label: 'M', width: 1 },
71
+ { label: ',', width: 1 }, { label: '.', width: 1, code: 'Period' }, { label: '/', width: 1, code: 'Slash' }, { label: 'Shift', width: 2.5, code: 'ShiftRight' },
72
+ ],
73
+ [
74
+ { label: 'Ctrl', width: 1.25, code: 'ControlLeft' }, { label: 'Win', width: 1.25, code: 'MetaLeft' }, { label: 'Alt', width: 1.25, code: 'AltLeft' },
75
+ { label: 'Space', width: 6.25, code: 'Space' },
76
+ { label: 'Alt', width: 1.25, code: 'AltRight' }, { label: 'Fn', width: 1.25 }, { label: 'Menu', width: 1.25, code: 'ContextMenu' }, { label: 'Ctrl', width: 1.25, code: 'ControlRight' },
77
+ ]
78
+ ]
79
+
80
+ const functionRows: Key[][] = [
81
+ [{ label: 'PrtSc', width: 1, code: 'PrintScreen' }, { label: 'ScrLk', width: 1, code: 'ScrollLock' }, { label: 'Pause', width: 1, code: 'Pause' }],
82
+ [{ label: 'Ins', width: 1 }, { label: 'Home', width: 1 }, { label: 'PgUp', width: 1 }],
83
+ [{ label: 'Del', width: 1 }, { label: 'End', width: 1 }, { label: 'PgDn', width: 1 }],
84
+ [{ type: 'spacer', width: 3 }],
85
+ [{ type: 'spacer', width: 1 }, { label: '↑', width: 1, code: 'ArrowUp' }, { type: 'spacer', width: 1 }],
86
+ [{ label: '←', width: 1, code: 'ArrowLeft' }, { label: '↓', width: 1, code: 'ArrowDown' }, { label: '→', width: 1, code: 'ArrowRight' }],
87
+ ]
88
+
89
+ const numpadKeys: Key[] = [
90
+ { label: 'Num', width: 1, code: 'NumLock' }, { label: '/', width: 1, code: 'NumpadDivide' }, { label: '*', width: 1, code: 'NumpadMultiply' }, { label: '-', width: 1, code: 'NumpadSubtract' },
91
+ { label: '7', width: 1, code: 'Numpad7' }, { label: '8', width: 1, code: 'Numpad8' }, { label: '9', width: 1, code: 'Numpad9' }, { label: '+', width: 1, height: 2, code: 'NumpadAdd' },
92
+ { label: '4', width: 1, code: 'Numpad4' }, { label: '5', width: 1, code: 'Numpad5' }, { label: '6', width: 1, code: 'Numpad6' },
93
+ { label: '1', width: 1, code: 'Numpad1' }, { label: '2', width: 1, code: 'Numpad2' }, { label: '3', width: 1, code: 'Numpad3' }, { label: 'Enter', width: 1, height: 2, code: 'NumpadEnter' },
94
+ { label: '0', width: 2, code: 'Numpad0' }, { label: '.', width: 1, code: 'NumpadDecimal' },
95
+ ]
96
+
97
+ function getKeyLabel(key: Key) {
98
+ if (os !== 'mac') return key.label;
99
+
100
+ const macMap: Record<string, string> = {
101
+ 'Ctrl': 'control',
102
+ 'Win': 'option',
103
+ 'Alt': 'command',
104
+ 'Bkspc': 'delete',
105
+ 'Enter': 'return',
106
+ 'Caps': 'caps lock',
107
+ 'Shift': 'shift',
108
+ 'Menu': 'option',
109
+ 'Tab': 'tab',
110
+ 'Esc': 'esc',
111
+ };
112
+
113
+ const label = (key.label && macMap[key.label]) || key.label;
114
+
115
+ if (label === 'command') return 'cmd ⌘';
116
+ if (label === 'option') return 'opt ⌥';
117
+ if (label === 'control') return 'ctrl ⌃';
118
+ if (label === 'shift') return 'shift ⇧';
119
+ if (label === 'return') return 'return ↩';
120
+ if (label === 'delete') return 'delete ⌫';
121
+
122
+ return label;
123
+ }
124
+
125
+ function getKeyHighlight(key: Key) {
126
+ if (!key) return { active: false };
127
+
128
+ const code = key.code || key.label || '';
129
+ const label = key.label || '';
130
+ const macLabel = getKeyLabel(key) || '';
131
+
132
+ const isMatch = (list: string[]) => {
133
+ if (!list || !Array.isArray(list)) return false;
134
+ if (list.includes(code)) return true;
135
+ if (list.includes(label)) {
136
+ if (code.startsWith('Numpad') && /^\d$/.test(label)) return false;
137
+ return true;
138
+ }
139
+ return os === 'mac' && list.includes(macLabel);
140
+ };
141
+
142
+ if (isMatch(highlightedKeys)) {
143
+ return { active: true, color: highlightColor };
144
+ }
145
+
146
+ for (const group of groups) {
147
+ if (isMatch(group.keys)) {
148
+ return { active: true, color: group.color };
149
+ }
150
+ }
151
+
152
+ return { active: false };
153
+ }
154
+
155
+ const displayMainRows = variant === '60'
156
+ ? [
157
+ [{ label: 'Esc', width: 1, code: 'Escape' }, ...(mainRows[1] || []).slice(1)],
158
+ ...mainRows.slice(2)
159
+ ]
160
+ : mainRows;
161
+
162
+
163
+ interface RenderKey extends Key {
164
+ x: number;
165
+ y: number;
166
+ w: number;
167
+ h: number;
168
+ }
169
+
170
+ function processRows(rows: Key[][], startX: number, startY: number): RenderKey[] {
171
+ const result: RenderKey[] = [];
172
+ let currentY = startY;
173
+
174
+ for (const row of rows) {
175
+ let currentX = startX;
176
+ for (const key of row) {
177
+ const w = key.width || 1;
178
+ const h = key.height || 1;
179
+ const widthPx = w * keySize + (w - 1) * keyGap;
180
+ const heightPx = h * keySize + (h - 1) * keyGap;
181
+
182
+ if (key.type !== 'spacer') {
183
+ result.push({
184
+ ...key,
185
+ x: currentX,
186
+ y: currentY,
187
+ w: widthPx,
188
+ h: heightPx
189
+ });
190
+ }
191
+ currentX += widthPx + keyGap;
192
+ }
193
+ currentY += keySize + keyGap;
194
+ }
195
+ return result;
196
+ }
197
+
198
+ const mainRenderKeys = processRows(displayMainRows, 0, 0);
199
+ const mainHeight = displayMainRows.length * (keySize + keyGap);
200
+
201
+ let secondaryKeys: RenderKey[] = [];
202
+ let numpadRenderKeys: RenderKey[] = [];
203
+ let totalWidth = (15 * keySize) + (14 * keyGap);
204
+ let finalHeight = mainHeight;
205
+
206
+ if (variant === 'full') {
207
+ const secondaryY = mainHeight + sectionGap;
208
+ secondaryKeys = processRows(functionRows, 0, secondaryY);
209
+
210
+ const numpadX = (3 * keySize) + (3 * keyGap) + sectionGap;
211
+
212
+ numpadKeys.forEach((key, i) => {
213
+ const k = key as Key;
214
+ const w = k.width || 1;
215
+ const h = k.height || 1;
216
+
217
+ const positions = [
218
+ [0,0], [1,0], [2,0], [3,0],
219
+ [0,1], [1,1], [2,1], [3,1],
220
+ [0,2], [1,2], [2,2],
221
+ [0,3], [1,3], [2,3], [3,3],
222
+ [0,4], [2,4]
223
+ ];
224
+
225
+ const pxOffset = positions[i]?.[0] ?? 0;
226
+ const pyOffset = positions[i]?.[1] ?? 0;
227
+
228
+ const px = numpadX + pxOffset * (keySize + keyGap);
229
+ const py = secondaryY + (pyOffset + 1) * (keySize + keyGap);
230
+
231
+ numpadRenderKeys.push({
232
+ ...k,
233
+ x: px,
234
+ y: py,
235
+ w: w * keySize + (w - 1) * keyGap,
236
+ h: h * keySize + (h - 1) * keyGap
237
+ });
238
+ });
239
+
240
+ totalWidth = Math.max(totalWidth, numpadX + (4 * keySize) + (3 * keyGap));
241
+ finalHeight = secondaryY + (6 * keySize) + (5 * keyGap);
242
+ }
243
+ ---
244
+
245
+ <div class="keyboard-wrapper">
246
+ <div class="keyboard-container">
247
+ <svg
248
+ viewBox={`-16 -16 ${totalWidth + 32} ${finalHeight + 64}`}
249
+ class="keyboard-svg"
250
+ preserveAspectRatio="xMidYMid meet"
251
+ >
252
+ {backgroundColor && backgroundColor !== 'transparent' && (
253
+ <rect
254
+ x="-16" y="-16"
255
+ width={totalWidth + 32}
256
+ height={finalHeight + 64}
257
+ fill={backgroundColor}
258
+ rx="12"
259
+ />
260
+ )}
261
+
262
+ {[...mainRenderKeys, ...secondaryKeys, ...numpadRenderKeys].map((key) => {
263
+ const highlight = getKeyHighlight(key);
264
+ const color = highlight.active ? (highlight.color || highlightColor) : '#2a2a3e';
265
+ const label = getKeyLabel(key);
266
+
267
+ return (
268
+ <g class={`kb-key-group ${highlight.active ? 'highlighted' : ''}`}>
269
+ {/* Key Base / Shadow */}
270
+ <rect
271
+ x={key.x}
272
+ y={key.y + 1}
273
+ width={key.w}
274
+ height={key.h}
275
+ rx="4"
276
+ fill="#1a1a2e"
277
+ />
278
+ {/* Key Face */}
279
+ <rect
280
+ x={key.x}
281
+ y={key.y}
282
+ width={key.w}
283
+ height={key.h}
284
+ rx="4"
285
+ fill={color}
286
+ stroke={highlight.active ? "#ffffff66" : "#3a3a4e"}
287
+ stroke-width="1"
288
+ />
289
+ {label && (
290
+ <text
291
+ x={key.x + key.w / 2}
292
+ y={key.y + key.h / 2}
293
+ text-anchor="middle"
294
+ dominant-baseline="central"
295
+ class="kb-key-label"
296
+ fill={highlight.active ? "#fff" : "#e0e0e0"}
297
+ >
298
+ {label}
299
+ </text>
300
+ )}
301
+ </g>
302
+ );
303
+ })}
304
+
305
+ </svg>
306
+ </div>
307
+
308
+ {groups.some(g => g.label) && (
309
+ <div class="flex flex-wrap justify-center gap-x-6 gap-y-3 mt-6 w-full">
310
+ {groups.filter(g => g.label).map(group => (
311
+ <div class="flex items-center gap-2 m-0 p-0 text-[10px] text-[#a0a0b0] uppercase tracking-[0.05em] font-medium whitespace-nowrap leading-none">
312
+ <svg width="8" height="8" class="flex-shrink-0 block">
313
+ <rect width="8" height="8" rx="2" fill={group.color || '#6366f1'} />
314
+ </svg>
315
+ <span class="m-0 p-0 leading-none inline-block">{group.label}</span>
316
+ </div>
317
+ ))}
318
+ </div>
319
+ )}
320
+ </div>
321
+
@@ -1,126 +1,125 @@
1
- /// <reference path="./locals.d.ts" />
2
- import type { StarlightPlugin, StarlightUserConfig } from "@astrojs/starlight/types"
3
- import virtual from "vite-plugin-virtual"
4
- import path from "node:path"
5
- import { fileURLToPath } from "node:url"
6
- import { z } from "astro/zod"
7
-
8
- import {
9
- StarlightSidebarTopicsConfigSchema,
10
- StarlightSidebarTopicsOptionsSchema,
11
- type StarlightSidebarTopicsUserConfig,
12
- type StarlightSidebarTopicsUserOptions
13
- } from "./libs/config"
14
- import { throwPluginError } from "./libs/plugin"
15
- import { vitePluginStarlightSidebarTopics } from "./libs/vite"
16
-
17
- export type {
18
- StarlightSidebarTopicsConfig,
19
- StarlightSidebarTopicsUserConfig,
20
- StarlightSidebarTopicsOptions,
21
- StarlightSidebarTopicsUserOptions
22
- } from "./libs/config"
23
-
24
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
25
-
26
- export interface StarlightAddonsConfig {
27
- copy?: boolean
28
- share?: boolean
29
- // Merged config for Topics
30
- topics?: StarlightSidebarTopicsUserConfig
31
- topicOptions?: StarlightSidebarTopicsUserOptions
32
- }
33
-
34
- export default function starlightAddons(userConfig?: StarlightAddonsConfig): StarlightPlugin {
35
- // 1. Setup default and merged config for Addons
36
- const defaultAddonConfig: StarlightAddonsConfig = {
37
- copy: true,
38
- share: true
39
- }
40
-
41
- const addonConfig = { ...defaultAddonConfig, ...userConfig }
42
-
43
- // 2. Validate Sidebar Topics configurations if they exist
44
- const parsedTopics = StarlightSidebarTopicsConfigSchema.safeParse(addonConfig.topics || [])
45
- if (!parsedTopics.success) {
46
- throwPluginError(
47
- `Invalid topics config: ${parsedTopics.error.issues.map((i) => i.message).join("\n")}`
48
- )
49
- }
50
-
51
- const parsedOptions = StarlightSidebarTopicsOptionsSchema.safeParse(addonConfig.topicOptions)
52
- if (!parsedOptions.success) {
53
- throwPluginError(`Invalid topic options: ${z.prettifyError(parsedOptions.error)}`)
54
- }
55
-
56
- const topicsData = parsedTopics.data
57
- const optionsData = parsedOptions.data
58
-
59
- return {
60
- name: "rimelight-ui-starlight-addons",
61
- hooks: {
62
- "config:setup"({
63
- addIntegration,
64
- updateConfig,
65
- logger,
66
- addRouteMiddleware,
67
- command,
68
- config: starlightConfig
69
- }) {
70
- // --- Sidebar Topics Logic ---
71
- if ((command === "dev" || command === "build") && topicsData.length > 0) {
72
- if (starlightConfig.sidebar) {
73
- throwPluginError(
74
- "Sidebar detected. To use topics, move your sidebar items into the topics config."
75
- )
76
- }
77
-
78
- const topicSidebar: StarlightUserConfig["sidebar"] = topicsData.map((topic, index) => {
79
- return "items" in topic
80
- ? { label: String(index), items: topic.items }
81
- : { label: String(index), items: [] }
82
- })
83
-
84
- updateConfig({
85
- sidebar: topicSidebar,
86
- components: {
87
- Sidebar: `starlight-sidebar-topics/overrides/Sidebar.astro`
88
- }
89
- })
90
- }
91
-
92
- // --- Addons Logic ---
93
- if (!addonConfig.copy && !addonConfig.share) {
94
- logger.warn("StarlightAddons: No features enabled.")
95
- }
96
-
97
- updateConfig({
98
- components: {
99
- // This will merge with the Sidebar override if both exist
100
- PageTitle: path.join(__dirname, "PageTitle.astro")
101
- }
102
- })
103
-
104
- // --- Unified Integration ---
105
- addIntegration({
106
- name: "rimelight-ui-starlight-addons-integration",
107
- hooks: {
108
- "astro:config:setup": ({ updateConfig: updateAstroConfig }) => {
109
- updateAstroConfig({
110
- vite: {
111
- plugins: [
112
- virtual({
113
- "virtual:rimelight-starlight-addons-config": `export default ${JSON.stringify(addonConfig)}`
114
- }),
115
- // Pass the validated topic data to the vite plugin
116
- vitePluginStarlightSidebarTopics(topicsData, optionsData)
117
- ]
118
- }
119
- } as Record<string, unknown>)
120
- }
121
- }
122
- })
123
- }
124
- }
125
- }
126
- }
1
+ /// <reference path="./locals.d.ts" />
2
+ import type { StarlightPlugin, StarlightUserConfig } from "@astrojs/starlight/types"
3
+ import virtual from "vite-plugin-virtual"
4
+ import path from "node:path"
5
+ import { fileURLToPath } from "node:url"
6
+ import { z } from "astro/zod"
7
+
8
+ import {
9
+ StarlightSidebarTopicsConfigSchema,
10
+ StarlightSidebarTopicsOptionsSchema,
11
+ type StarlightSidebarTopicsUserConfig,
12
+ type StarlightSidebarTopicsUserOptions
13
+ } from "./libs/config"
14
+ import { throwPluginError } from "./libs/plugin"
15
+ import { vitePluginStarlightSidebarTopics } from "./libs/vite"
16
+
17
+ export type {
18
+ StarlightSidebarTopicsConfig,
19
+ StarlightSidebarTopicsUserConfig,
20
+ StarlightSidebarTopicsOptions,
21
+ StarlightSidebarTopicsUserOptions
22
+ } from "./libs/config"
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
25
+
26
+ export interface StarlightAddonsConfig {
27
+ copy?: boolean
28
+ share?: boolean
29
+ // Merged config for Topics
30
+ topics?: StarlightSidebarTopicsUserConfig
31
+ topicOptions?: StarlightSidebarTopicsUserOptions
32
+ }
33
+
34
+ export default function starlightAddons(userConfig?: StarlightAddonsConfig): StarlightPlugin {
35
+ // 1. Setup default and merged config for Addons
36
+ const defaultAddonConfig: StarlightAddonsConfig = {
37
+ copy: true,
38
+ share: true
39
+ }
40
+
41
+ const addonConfig = { ...defaultAddonConfig, ...userConfig }
42
+
43
+ // 2. Validate Sidebar Topics configurations if they exist
44
+ const parsedTopics = StarlightSidebarTopicsConfigSchema.safeParse(addonConfig.topics || [])
45
+ if (!parsedTopics.success) {
46
+ throwPluginError(
47
+ `Invalid topics config: ${parsedTopics.error.issues.map((i) => i.message).join("\n")}`
48
+ )
49
+ }
50
+
51
+ const parsedOptions = StarlightSidebarTopicsOptionsSchema.safeParse(addonConfig.topicOptions)
52
+ if (!parsedOptions.success) {
53
+ throwPluginError(`Invalid topic options: ${z.prettifyError(parsedOptions.error)}`)
54
+ }
55
+
56
+ const topicsData = parsedTopics.data
57
+ const optionsData = parsedOptions.data
58
+
59
+ return {
60
+ name: "rimelight-ui-starlight-addons",
61
+ hooks: {
62
+ "config:setup"({
63
+ addIntegration,
64
+ updateConfig,
65
+ logger,
66
+ command,
67
+ config: starlightConfig
68
+ }) {
69
+ // --- Sidebar Topics Logic ---
70
+ if ((command === "dev" || command === "build") && topicsData.length > 0) {
71
+ if (starlightConfig.sidebar) {
72
+ throwPluginError(
73
+ "Sidebar detected. To use topics, move your sidebar items into the topics config."
74
+ )
75
+ }
76
+
77
+ const topicSidebar: StarlightUserConfig["sidebar"] = topicsData.map((topic, index) => {
78
+ return "items" in topic
79
+ ? { label: String(index), items: topic.items }
80
+ : { label: String(index), items: [] }
81
+ })
82
+
83
+ updateConfig({
84
+ sidebar: topicSidebar,
85
+ components: {
86
+ Sidebar: `starlight-sidebar-topics/overrides/Sidebar.astro`
87
+ }
88
+ })
89
+ }
90
+
91
+ // --- Addons Logic ---
92
+ if (!addonConfig.copy && !addonConfig.share) {
93
+ logger.warn("StarlightAddons: No features enabled.")
94
+ }
95
+
96
+ updateConfig({
97
+ components: {
98
+ // This will merge with the Sidebar override if both exist
99
+ PageTitle: path.join(__dirname, "PageTitle.astro")
100
+ }
101
+ })
102
+
103
+ // --- Unified Integration ---
104
+ addIntegration({
105
+ name: "rimelight-ui-starlight-addons-integration",
106
+ hooks: {
107
+ "astro:config:setup": ({ updateConfig: updateAstroConfig }) => {
108
+ updateAstroConfig({
109
+ vite: {
110
+ plugins: [
111
+ virtual({
112
+ "virtual:rimelight-starlight-addons-config": `export default ${JSON.stringify(addonConfig)}`
113
+ }),
114
+ // Pass the validated topic data to the vite plugin
115
+ vitePluginStarlightSidebarTopics(topicsData, optionsData)
116
+ ]
117
+ }
118
+ } as Record<string, unknown>)
119
+ }
120
+ }
121
+ })
122
+ }
123
+ }
124
+ }
125
+ }