@kurot/ui 3.2.0 → 3.4.0

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +74 -8
  3. package/dist/kurot/components/BitmapLabel.d.ts +2 -0
  4. package/dist/kurot/components/BitmapLabel.d.ts.map +1 -1
  5. package/dist/kurot/components/BitmapLabel.js +17 -1
  6. package/dist/kurot/components/BitmapLabel.js.map +1 -1
  7. package/dist/kurot/components/ComboBox.d.ts.map +1 -1
  8. package/dist/kurot/components/ComboBox.js +5 -3
  9. package/dist/kurot/components/ComboBox.js.map +1 -1
  10. package/dist/kurot/components/Component.d.ts +1 -0
  11. package/dist/kurot/components/Component.d.ts.map +1 -1
  12. package/dist/kurot/components/Component.js +3 -0
  13. package/dist/kurot/components/Component.js.map +1 -1
  14. package/dist/kurot/components/Group.d.ts +1 -0
  15. package/dist/kurot/components/Group.d.ts.map +1 -1
  16. package/dist/kurot/components/Group.js +3 -0
  17. package/dist/kurot/components/Group.js.map +1 -1
  18. package/dist/kurot/components/RichLabel.d.ts +51 -0
  19. package/dist/kurot/components/RichLabel.d.ts.map +1 -0
  20. package/dist/kurot/components/RichLabel.js +172 -0
  21. package/dist/kurot/components/RichLabel.js.map +1 -0
  22. package/dist/kurot/components/index.d.ts +1 -0
  23. package/dist/kurot/components/index.d.ts.map +1 -1
  24. package/dist/kurot/components/index.js +1 -0
  25. package/dist/kurot/components/index.js.map +1 -1
  26. package/dist/kurot/core/UIState.d.ts +4 -0
  27. package/dist/kurot/core/UIState.d.ts.map +1 -1
  28. package/dist/kurot/core/UIState.js +15 -7
  29. package/dist/kurot/core/UIState.js.map +1 -1
  30. package/dist/kurot/core/fit-transformed-bounds.d.ts +14 -0
  31. package/dist/kurot/core/fit-transformed-bounds.d.ts.map +1 -0
  32. package/dist/kurot/core/fit-transformed-bounds.js +149 -0
  33. package/dist/kurot/core/fit-transformed-bounds.js.map +1 -0
  34. package/docs/ai-context.md +43 -7
  35. package/docs/architecture.md +31 -4
  36. package/docs/bitmap-label.md +11 -5
  37. package/docs/rich-label.md +77 -0
  38. package/package.json +7 -5
@@ -1,16 +1,24 @@
1
1
  # @kurot/ui — AI context map
2
2
 
3
+ Source prepares UI 3.4.0 and installs published Core 2.4.0 with a matching
4
+ registry lockfile, without local overrides. The released baseline below is
5
+ historical. Read
6
+ [centered flips](../../../docs/centered-flips.md) before changing transforms,
7
+ reflection frames, authored flags or dependency adoption.
8
+
3
9
  Read this before exploring `src/`. It is a compressed map so an agent
4
10
  unfamiliar with Kurot does not need to re-derive the architecture from scratch
5
11
  each session. Treat the package source and its `src/index.ts` barrel as the
6
12
  authority for current behavior and exports; this file provides the compressed
7
13
  map, runtime contracts and task→file lookup.
8
14
 
9
- Package identity: `@kurot/ui@3.2.0`, EUI-compatible UI framework on top of
10
- `@kurot/core`. Peer-depends on `@kurot/core@^2.2.0`. Rewritten with standard class
15
+ Package identity: `@kurot/ui@3.4.0`, EUI-compatible UI framework on top of
16
+ `@kurot/core`. Peer-depends on `@kurot/core@^2.4.0`. Rewritten with standard class
11
17
  inheritance and delegation — no namespace mixins, no prototype copying.
12
- Version 3.2.0 is prepared for publication against published Core 2.2.0;
13
- source metadata alone does not confirm UI publication.
18
+ Version 3.3.1 is preserved in commit 60e6404 and fixes transformed parent
19
+ allocations. It has not been published; UI 3.4.0 includes the same correction. Version 3.3.0 adds RichLabel and tests against published Core 2.3.1 through its
20
+ development installation and lockfile, without overrides. Version 3.2.0 is published with BitmapLabel against published Core 2.2.0,
21
+ without local dependency overrides. Published UI 3.1.0 does not contain BitmapLabel.
14
22
 
15
23
  Source root: `src/kurot/`. Public API: `src/index.ts` is a flat re-export of
16
24
  7 barrels — `core`, `layouts`, `components`, `events`, `states`, `collections`,
@@ -26,7 +34,7 @@ src/kurot/
26
34
  │ Validator/validator (render-preparation validation scheduler),
27
35
  │ Theme/getTheme()/setTheme(), IViewport, IAssetAdapter/IThemeAdapter.
28
36
  ├── components/ Group, Component (delegation core — see §2), Skin, and
29
- │ concrete widgets: Button, Label, BitmapLabel, CheckBox, RadioButton,
37
+ │ concrete widgets: Button, Label, BitmapLabel, RichLabel, CheckBox, RadioButton,
30
38
  │ ToggleButton/ToggleSwitch, ProgressBar, HSlider/VSlider,
31
39
  │ Rect, Image, EditableText, TextInput, Panel, ViewStack,
32
40
  │ Scroller, UILayer, DataGroup, List, TabBar, ComboBox,
@@ -48,6 +56,12 @@ src/kurot/
48
56
 
49
57
  ## 2. Non-obvious current behavior
50
58
 
59
+ - `flipX`/`flipY` are native Core booleans inherited by every UI display
60
+ component. Group and Component provide their validated, unscaled actual frame
61
+ through `$getFlipBounds()`. `UIState.getActualBounds()` reads this frame without
62
+ validating recursively. Layout uses the authored matrix, independent of flips;
63
+ negative scale remains anchor-based. Resizing moves the reflection center.
64
+
51
65
  - **`Skin` is NOT a `Group`/DisplayObject subclass.** `components/Skin.ts`
52
66
  defines `class Skin extends EventDispatcher<SkinEvents>` — a plain data
53
67
  holder, not a visual container. A skin's
@@ -93,6 +107,13 @@ skin)` signature, but `Group._commitCurrentState()` passes `this` cast
93
107
  - Anchor/percent constraints (`left`/`right`/`percentWidth`, etc.) have zero
94
108
  effect until the component is added to a `Group` that has a `layout`
95
109
  assigned. Setting them on a standalone/unparented component is a no-op.
110
+ - **Since 3.3.1: transformed allocations use parent-space dimensions.**
111
+ `core/fit-transformed-bounds.ts` converts them to local sizes for negative scale,
112
+ rotation and skew. UIState tracks the allocated local axes so width/height
113
+ reads do not discard a rotated one-axis allocation. Anchor/translation affect
114
+ positioning, not size. Incompatible aspect ratios fit the largest contained
115
+ local rectangle; local minima win when containment is impossible. The published
116
+ UI 3.3.0 still falls back to preferred dimensions for non-identity transforms.
96
117
  - `isUIComponent()` is duck-typed (`'ui' in obj`) — any object with a `.ui`
97
118
  property passes, not necessarily a real `Group`/`Component`.
98
119
  - **Virtual layout defaults to OFF.**
@@ -143,7 +164,7 @@ Flat re-export of 7 barrels, in this order: `core`, `layouts`, `components`,
143
164
 
144
165
  - **core**: `IUIComponent`, `IUIOwner`, `UIState`, `isUIComponent`, `Validator`/`validator`, `Theme`/`getTheme`/`setTheme`, `IViewport`, `IAssetAdapter`/`DefaultAssetAdapter`, `setAssetAdapter`/`getAssetAdapter`, `IThemeAdapter`/`DefaultThemeAdapter`, `Direction`, `ScrollPolicy`, `IDisplayText`, `IItemRenderer`.
145
166
  - **layouts**: `ILayoutTarget`, `LayoutBase`, `BasicLayout`, `LinearLayoutBase`, `VerticalLayout`, `HorizontalLayout`, `TileLayout`, `ColumnAlign`, `RowAlign`, `JustifyAlign`, `TileOrientation`.
146
- - **components**: `Group`/`GroupEvents`, `Component`/`ComponentEvents`, `Skin`/`SkinEvents`; `Button`, `Label`/`TextFitMode` (type), `BitmapLabel`, `CheckBox`, `RadioButton`/`RadioButtonGroup`, `ToggleButton`, `ToggleSwitch`, `ProgressBar`, `HSlider`/`VSlider`/`SliderBase`, `Rect`, `Image`, `EditableText`, `TextInput`, `Panel`, `ViewStack`, `Scroller`, `TouchScroll`, `UILayer`, `DataGroup`, `List`/`ListBase`, `TabBar`, `ComboBox`, `ItemRenderer`, `HScrollBar`/`VScrollBar`/`ScrollBarBase`, `Animation`, `Range`.
167
+ - **components**: `Group`/`GroupEvents`, `Component`/`ComponentEvents`, `Skin`/`SkinEvents`; `Button`, `Label`/`TextFitMode` (type), `BitmapLabel`, `RichLabel`, `CheckBox`, `RadioButton`/`RadioButtonGroup`, `ToggleButton`, `ToggleSwitch`, `ProgressBar`, `HSlider`/`VSlider`/`SliderBase`, `Rect`, `Image`, `EditableText`, `TextInput`, `Panel`, `ViewStack`, `Scroller`, `TouchScroll`, `UILayer`, `DataGroup`, `List`/`ListBase`, `TabBar`, `ComboBox`, `ItemRenderer`, `HScrollBar`/`VScrollBar`/`ScrollBarBase`, `Animation`, `Range`.
147
168
  - **events**: `UIEvent`, `ItemTapEvent`, `CollectionEvent`/`CollectionEventKind`, `PropertyEvent`, `ScrollerThrowEvent`.
148
169
  - **states**: `State`, `IOverride`, `SetProperty`, `SetStateProperty`, `AddItems`.
149
170
  - **collections**: `ICollection`, `ArrayCollection`.
@@ -206,7 +227,7 @@ automatic bounds are not fed back as fit constraints.
206
227
 
207
228
  `label.invalidateSize()` also invalidates Core line metrics. Call it after
208
229
  late font loading, even if the family name did not change. This requires
209
- Core >= 2.1.0 for that API; UI 3.2.0's package requirement is Core ^2.2.0.
230
+ Core >= 2.1.0 for that API; UI 3.3.0's package requirement is Core ^2.3.0.
210
231
  There is no global font-readiness listener.
211
232
 
212
233
  See [Label text layout](label-text-layout.md) for fit bounds, state restoration,
@@ -222,3 +243,18 @@ using one BitmapText child and the configured Core resource singleton for string
222
243
  font names. Stale async results are guarded by request generation. Core ^2.2.0
223
244
  is required; local Core overrides have been removed. Published UI 3.1.0 does
224
245
  not contain it. KUI catalog, installed compilers and Editor adoption are separate.
246
+
247
+ ## Rich labels in 3.3.0
248
+
249
+ [rich-label.md](rich-label.md) defines RichLabel, an independent Component using
250
+ one native TextField. Only textFlow supplies content; no Label text/appearance
251
+ properties, textFit or textStyle. Reads and assignments copy runs and styles;
252
+ [] clears content. Wrapping is continuous across styles. Measurement uses Core
253
+ 2.3.0's pure measureText with parent width, explicit width or maxWidth; cached
254
+ metrics clear on invalidateSize, including after fonts load. Geometry, multiline,
255
+ wordWrap, lineSpacing, textAlign and verticalAlign remain component-level.
256
+
257
+ Task → `components/RichLabel.ts`, `test/RichLabel.test.ts`,
258
+ `test/browser/text-labels.spec.ts`. Run `pnpm test:text-labels` after building
259
+ Core and UI. BitmapLabel automatic measurement now uses maxWidth too. The KUI
260
+ catalog, CLI and Editor must adopt these native components in a later phase.
@@ -1,12 +1,14 @@
1
1
  # @kurot/ui architecture
2
2
 
3
- > Package version: 3.2.0, with peerDependency `@kurot/core: ^2.2.0`.
4
- > This release is prepared against published Core 2.2.0; UI publication is not yet confirmed.
3
+ > Package version: 3.4.0 (unpublished), with peerDependency `@kurot/core: ^2.4.0`.
4
+ > Development installs published Core 2.4.0 with a matching registry lockfile.
5
+ > No local Core override is needed for builds or centered-flip checks.
5
6
  > See [CHANGELOG.md](../CHANGELOG.md) for release-by-release changes.
6
7
  > The [AI context map](./ai-context.md) provides directory, behavior, terminology
7
8
  > and task-to-file references. This document explains design decisions and internal
8
9
  > mechanisms for human readers; the two documents complement each other.
9
- > Version 3.2.0 exports BitmapLabel for native code and programmatic skins.
10
+ > Version 3.3.0 also exports independent [RichLabel](./rich-label.md).
11
+ > Version 3.2.0 introduced BitmapLabel for native code and programmatic skins.
10
12
  > See [bitmap-label.md](./bitmap-label.md) for its resource and ownership contract.
11
13
 
12
14
  ---
@@ -305,6 +307,23 @@ A trailing percent sign selects percentage calculation; otherwise the value is
305
307
  converted to a number. There is no separate runtime type tag for percentages
306
308
  versus pixels.
307
309
 
310
+ The 3.3.1 transform-allocation correction uses
311
+ `core/fit-transformed-bounds.ts` from UIState. Allocated dimensions describe the
312
+ parent-space rectangle, while explicit, preferred and minimum/maximum sizes stay
313
+ local. The solver uses the absolute linear matrix coefficients to obtain that
314
+ rectangle's width and height. Anchors and translation affect only its position.
315
+ It fills both requested axes when possible, otherwise chooses the largest local
316
+ rectangle contained by the allocation. Local minimum sizes take precedence if
317
+ no contained rectangle can satisfy them. With one allocated axis, an authored
318
+ single local dimension is retained when possible; the unconstrained parent extent
319
+ is minimized otherwise. Unallocated transforms preserve local measurement.
320
+
321
+ UIState also maps the allocation flags to the affected local axes. A quarter-turn
322
+ width allocation controls local height, so reading height must retain the fitted
323
+ value rather than restoring the authored height. A zero scale column keeps its
324
+ natural local dimension without division by zero. Group and Component share
325
+ this behavior, including Image, text, buttons and other component subclasses.
326
+
308
327
  LinearLayoutBase.flexChildrenProportionally(), shared by VerticalLayout and
309
328
  HorizontalLayout, iteratively allocates percentages with min/max constraints.
310
329
  A do...while loop identifies children whose proportional allocation exceeds a
@@ -371,6 +390,7 @@ including intermediate base classes.
371
390
  | `Image` | Displays bitmap data resolved through IAssetAdapter |
372
391
  | `Label` | Text display wrapping one TextField |
373
392
  | `BitmapLabel` | Bitmap-font label wrapping one BitmapText; requires Core 2.2.0 or later |
393
+ | `RichLabel` | Independent Component with textFlow content and pure, cached TextField measurement |
374
394
  | `EditableText extends Label` | Editable text with prompt support |
375
395
  | `Button` | Clickable up/down/disabled states; toggle enables automatic selected changes |
376
396
  | `ToggleButton extends Button` | Defaults toggle to true and toggles selection on click |
@@ -449,7 +469,7 @@ file and case counts.
449
469
  | Skins and states | Skin, SkinAlignment (real CLI template skins), SkinMeasurement, AddItems |
450
470
  | Data binding | Binding, Watcher |
451
471
  | Collections and data-driven components | ArrayCollection, DataGroup, ListBase, ItemRenderer, ComboBox, TabBar, ViewStack |
452
- | Individual components | RadioButton, Range, Slider, ProgressBar, Scroller, Label, BitmapLabel, TextInput |
472
+ | Individual components | RadioButton, Range, Slider, ProgressBar, Scroller, Label, BitmapLabel, RichLabel, TextInput |
453
473
  | Text fitting | ButtonLabelTextFit, LabelTextFit, LabelTextFitBounds |
454
474
  | Cross-component behavior | Enabled (EUI-aligned enabled/touchEnabled/touchChildren behavior), EventMapOverride, GestureLifecycle, TransformLayout, ScrollAndVirtualLayout |
455
475
 
@@ -465,3 +485,10 @@ static UI, 240-node transform/alpha animation and a virtual list with 10,000 rec
465
485
  It records frame/render time, draw calls, validation-phase calls and ItemRenderer
466
486
  creation/reuse. It is a regression baseline for this UI implementation, rather
467
487
  than a ranking across UI frameworks.
488
+
489
+ ### Text component browser validation
490
+
491
+ Build Core and UI, then run `pnpm test:text-labels` from this package. The fixture
492
+ bundles built ESM with minification and keepNames=false, verifies actual pixels
493
+ through Canvas 2D, WebGL 1 and WebGL 2, and checks automatic bounds, edits and
494
+ empty content. Browser screenshots go to ignored test-results, not the package.
@@ -1,10 +1,16 @@
1
1
  # BitmapLabel
2
2
 
3
3
  Available in UI 3.2.0 with `@kurot/core ^2.2.0`. Core resolves its published
4
- @kurot/bitmap-font dependency from npm. UI 3.2.0 is prepared for publication;
4
+ @kurot/bitmap-font dependency from npm. UI 3.2.0 is published;
5
5
  published UI 3.1.0 does not contain this component. Core 2.1.1 does not contain
6
6
  its required BitmapText rendering.
7
7
 
8
+ UI 3.3.0 retains this API and raises the package's Core minimum to ^2.3.0 for
9
+ RichLabel. During automatic sizing it also uses maxWidth when neither a parent
10
+ width nor an explicit width is present, so wrapped height matches rendering.
11
+ Changing an authored width also invalidates automatic height after layout.
12
+ UI 3.3.0 builds and tests against published Core 2.3.1 without local overrides.
13
+
8
14
  ```ts
9
15
  import { BitmapLabel } from '@kurot/ui';
10
16
 
@@ -35,7 +41,7 @@ DisplayObject tint. Alignments position glyphs without scaling them. Set scaleX
35
41
  and scaleY for decorative number sizing. Default multiline=true; explicit false
36
42
  keeps the first hard-separated line unwrapped.
37
43
 
38
- This initial change exposes a native UI component and supports programmatic
39
- skins. The ui-document built-in catalog, CLI KUI tag registry, Editor and
40
- ui-runtime materializers do not yet adopt BitmapLabel. Those require coordinated
41
- consumer releases; do not assume an installed compiler accepts the XML tag.
44
+ Published ui-document 0.12.0, CLI 3.4.0 and ui-runtime 0.9.0 support BitmapLabel
45
+ authoring, KUI compilation and materialization. Earlier compilers do not accept
46
+ this built-in XML tag; update applications explicitly when adopting it. Editor
47
+ controls are owned by the separate application.
@@ -0,0 +1,77 @@
1
+ # RichLabel
2
+
3
+ Native API introduced in UI 3.3.0, requiring Core ^2.3.0. Core 2.3.1 is
4
+ published and installed from npm for this release's build and verification.
5
+
6
+ ```ts
7
+ import { RichLabel } from '@kurot/ui';
8
+
9
+ const label = new RichLabel([
10
+ { text: 'Warning: ', style: { size: 20, bold: true, textColor: 0xff9900 } },
11
+ { text: 'read this before continuing.', style: { size: 20, italic: true } },
12
+ ]);
13
+ label.maxWidth = 240;
14
+ group.addChild(label);
15
+ ```
16
+
17
+ ## Content and ownership
18
+
19
+ RichLabel extends Component independently, not Label. Its only content interface
20
+ is `textFlow: ITextElement[]`, using Core's text/style records. Whole-component
21
+ `text`, `fontFamily`, `size`, `bold`, `italic`, `textColor`, `textFit`, `minFontSize`
22
+ and `textStyle` are not exposed. Label presets do not apply to this component.
23
+
24
+ Runs can specify font family, size, bold, italic, text color, stroke color and
25
+ stroke width. Unspecified fields use the native TextField defaults captured at
26
+ construction. In particular, an unstyled run does not inherit the previous run.
27
+ All runs are laid out continuously; a style boundary does not introduce a word
28
+ boundary or a new line. No HTML or markdown parsing is performed.
29
+
30
+ The component copies runs and their styles on assignment and on reads. Mutating
31
+ an input array or a returned snapshot does not change the component. Reassign
32
+ an edited snapshot to apply it. Assigning [] clears content; assignment dispatches
33
+ PropertyEvent.PROPERTY_CHANGE for `textFlow` after the new content is installed.
34
+
35
+ ## Layout
36
+
37
+ Ordinary Component geometry, layout constraints, visibility and alpha remain
38
+ available, together with these text-layout properties:
39
+
40
+ | Property | Default | Contract |
41
+ | ---------------------- | --------- | ------------------------------------------------------------------------- |
42
+ | multiline | true | False shows the first hard-separated line without width wrapping. |
43
+ | wordWrap | true | Unicode line-break opportunities; false wraps between graphemes. |
44
+ | lineSpacing | 0 | Finite, nonnegative distance between lines. |
45
+ | textAlign | left | left, center or right. |
46
+ | verticalAlign | top | top, middle or bottom. |
47
+ | textWidth / textHeight | Read-only | Complete content metrics under the current width, before height clipping. |
48
+
49
+ Measurement uses parent-assigned width first, then explicit width, then a
50
+ configured maxWidth, otherwise unconstrained width. Automatic height includes
51
+ every wrapped line and inter-line spacing. Each line uses the largest font size
52
+ of its runs, rather than imposing the TextField base size. Hard line separators
53
+ and trailing blank lines follow the Core text contract. Core 2.3.1 corrects the
54
+ base size of unstyled blank runs between styled runs; the API minimum stays 2.3.0. Empty content measures
55
+ 0 × 0; Component minWidth/minHeight can still enlarge its layout bounds.
56
+
57
+ Fixed height clips drawing without discarding content. Alignment positions the
58
+ continuous text block within the assigned bounds. One native TextField renders
59
+ through Canvas 2D and WebGL; measurement never temporarily resizes that field.
60
+ Unchanged content metrics are cached until size/content invalidation or a width
61
+ change.
62
+
63
+ ## Font readiness and integration
64
+
65
+ Load project fonts before measuring where possible. If fonts become ready later,
66
+ call `label.invalidateSize()` to clear both component and native text metrics,
67
+ then allow normal layout validation. RichLabel does not load font files or
68
+ install global font-loading listeners.
69
+
70
+ Published ui-document 0.12.0, CLI 3.4.0 and ui-runtime 0.9.0 provide RichLabel
71
+ authoring, KUI compilation and materialization. Earlier versions lack these
72
+ built-in registrations. Editor controls are owned by the separate application;
73
+ all consumers retain textFlow ownership and separation from Label presets.
74
+
75
+ See [Core text layout](../../core/docs/text-layout.md) for Unicode wrapping,
76
+ single-line behavior and independent measurement. Run `pnpm test:text-labels`
77
+ after building Core and UI for minified Canvas/WebGL browser verification.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kurot/ui",
3
- "version": "3.2.0",
4
- "description": "EUI-compatible UI component framework for the Kurot game engine \u2014 skin-based components, layouts, data binding, view states",
3
+ "version": "3.4.0",
4
+ "description": "EUI-compatible UI component framework for the Kurot game engine — skin-based components, layouts, data binding, view states",
5
5
  "author": "Kelvin <kyia.x52@gmail.com>",
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -30,15 +30,17 @@
30
30
  "benchmark:compare": "playwright test --config examples/benchmark/playwright.config.ts",
31
31
  "benchmark:smoke": "UI_BENCHMARK_PROFILE=smoke playwright test --config examples/benchmark/playwright.config.ts",
32
32
  "build:benchmark": "vite --config vite.config.ts build",
33
- "prepublishOnly": "npm run clean && npm run build"
33
+ "prepublishOnly": "npm run clean && npm run build",
34
+ "test:text-labels": "playwright test test/browser --workers=1"
34
35
  },
35
36
  "peerDependencies": {
36
- "@kurot/core": "^2.2.0"
37
+ "@kurot/core": "^2.4.0"
37
38
  },
38
39
  "devDependencies": {
39
- "@kurot/core": "^2.2.0",
40
+ "@kurot/core": "^2.4.0",
40
41
  "@playwright/test": "1.62.1",
41
42
  "@types/node": "^22.0.0",
43
+ "esbuild": "^0.28.2",
42
44
  "happy-dom": "^20.8.9",
43
45
  "typescript": "^5.6.0",
44
46
  "vite": "^8.0.8",