@kurot/ui 3.0.0 → 3.2.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.
- package/CHANGELOG.md +78 -6
- package/README.md +154 -69
- package/dist/kurot/components/BitmapLabel.d.ts +46 -0
- package/dist/kurot/components/BitmapLabel.d.ts.map +1 -0
- package/dist/kurot/components/BitmapLabel.js +180 -0
- package/dist/kurot/components/BitmapLabel.js.map +1 -0
- package/dist/kurot/components/Label.d.ts +40 -0
- package/dist/kurot/components/Label.d.ts.map +1 -1
- package/dist/kurot/components/Label.js +182 -32
- package/dist/kurot/components/Label.js.map +1 -1
- package/dist/kurot/components/index.d.ts +2 -1
- package/dist/kurot/components/index.d.ts.map +1 -1
- package/dist/kurot/components/index.js +1 -0
- package/dist/kurot/components/index.js.map +1 -1
- package/dist/kurot/text/fit-label-text.d.ts +23 -0
- package/dist/kurot/text/fit-label-text.d.ts.map +1 -0
- package/dist/kurot/text/fit-label-text.js +36 -0
- package/dist/kurot/text/fit-label-text.js.map +1 -0
- package/docs/ai-context.md +224 -0
- package/docs/architecture.md +467 -0
- package/docs/bitmap-label.md +41 -0
- package/docs/label-text-layout.md +99 -0
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,79 @@ All notable changes to `@kurot/ui` are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [3.2.0] — 2026-10-08
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Export BitmapLabel, a native UI component wrapping Core BitmapText with normal
|
|
12
|
+
measurement, parent layout constraints, alignment, spacing and text bindings.
|
|
13
|
+
- Accept a caller-owned BitmapFont or a configured font-resource name. Resolve
|
|
14
|
+
preloaded fonts synchronously and load missing fonts through Core's resource
|
|
15
|
+
singleton, reporting completion and loading/type errors through events.
|
|
16
|
+
- Ignore superseded asynchronous font results, including A-to-B-to-A changes.
|
|
17
|
+
Font ownership remains with the resource cache or caller.
|
|
18
|
+
|
|
19
|
+
### Dependencies and migration
|
|
20
|
+
|
|
21
|
+
- Require `@kurot/core ^2.2.0` in peer and development dependencies for rendered
|
|
22
|
+
BitmapText, FontAnalyzer and pure text measurement. Upgrade older Core installs
|
|
23
|
+
and lockfiles before adopting UI 3.2.0.
|
|
24
|
+
- Remove the local Core dependency override and build against published Core.
|
|
25
|
+
UI continues to depend only on Core; bitmap-font is Core's dependency.
|
|
26
|
+
- BitmapLabel supports native code and programmatic skins. The ui-document
|
|
27
|
+
catalog, CLI KUI tags, Editor and ui-runtime materializers do not yet adopt it.
|
|
28
|
+
|
|
29
|
+
### Tests and documentation
|
|
30
|
+
|
|
31
|
+
- Cover layout and measurement, alignment, binding notifications, cached and
|
|
32
|
+
asynchronous font resolution, stale requests, invalid resources and errors.
|
|
33
|
+
- Translate architecture documentation to English and correct outdated Skin,
|
|
34
|
+
theme-adapter, validation and virtual-layout descriptions against source.
|
|
35
|
+
|
|
36
|
+
## [3.1.0] — 2026-10-05
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- Single-line Label `textFit="shrink"` and `minFontSize`, with derived
|
|
41
|
+
`renderedSize` and `textFitOverflow` observations after validation.
|
|
42
|
+
- Export the `TextFitMode` type (`none` or `shrink`) from the public barrel.
|
|
43
|
+
- Fit within actual label constraints, reserve outline allowance, restore the
|
|
44
|
+
authored size for shorter text, and refresh metrics after font readiness.
|
|
45
|
+
- Include public documentation in the npm package, including the Label text
|
|
46
|
+
contract, architecture and package context.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Label defaults to multiline; explicit false means one unwrapped first line.
|
|
51
|
+
EditableText keeps its single-line default and rejects shrinking.
|
|
52
|
+
- Preserve authored size through native state apply/remove and avoid feeding
|
|
53
|
+
automatic measured dimensions back into fitting.
|
|
54
|
+
|
|
55
|
+
### Migration
|
|
56
|
+
|
|
57
|
+
- Explicit `multiline="false"` now means one unwrapped first line. Remove the
|
|
58
|
+
flag or set it to true for text intended to wrap; files are not migrated.
|
|
59
|
+
- Set fitting policy on a Button's `labelDisplay` skin part. Multiline Labels
|
|
60
|
+
retain their authored size, and EditableText rejects `textFit="shrink"`.
|
|
61
|
+
- Load fonts before measurement where possible. After a font becomes ready
|
|
62
|
+
late, call `label.invalidateSize()` to refresh fitting and Core line metrics.
|
|
63
|
+
|
|
64
|
+
### Dependencies
|
|
65
|
+
|
|
66
|
+
- Require `@kurot/core@^2.1.0` in peer and development dependencies for
|
|
67
|
+
`TextField.invalidateTextMetrics()`. Core 2.0.x is no longer sufficient.
|
|
68
|
+
- KUI authoring uses ui-document 0.9.x and matching CLI/ui-runtime releases;
|
|
69
|
+
native UI still depends only on Core.
|
|
70
|
+
|
|
71
|
+
### Tests
|
|
72
|
+
|
|
73
|
+
- Verify native Button label fitting uses the label region, preserves authored
|
|
74
|
+
sizes through disabled-state transitions, and follows active skin replacement.
|
|
75
|
+
- Cover minimum overflow, fractional sizes, outlines, hard separators, password
|
|
76
|
+
display, late font readiness, automatic dimensions and parent layout changes.
|
|
77
|
+
- Verify real regular/bold fonts and Chinese fallback with 16 browser checks
|
|
78
|
+
each on WebGL and Canvas, including Unicode wrapping and state restoration.
|
|
79
|
+
|
|
7
80
|
## [3.0.0] — 2026-10-03
|
|
8
81
|
|
|
9
82
|
### Breaking
|
|
@@ -337,7 +410,6 @@ protected override onSkinRemoved(): void {
|
|
|
337
410
|
- **Button: remove dead `_autoRepeat` property** — getter/setter existed but no code consumed the value. Simplified `partAdded` to compare `partName` instead of `instance === this.labelDisplay` (eliminates non-null assertions).
|
|
338
411
|
- **ListBase: clean up `adjustSelection` and `dataProviderRefreshed`** — removed identical if/else branches and premature `PropertyEvent` dispatch (silent adjustment per egret semantics, events deferred to `commitProperties`).
|
|
339
412
|
|
|
340
|
-
|
|
341
413
|
## [1.0.6] — 2026-08-05
|
|
342
414
|
|
|
343
415
|
### Fixed
|
|
@@ -354,10 +426,10 @@ protected override onSkinRemoved(): void {
|
|
|
354
426
|
### Fixed
|
|
355
427
|
|
|
356
428
|
- **Component (`enabled` / `touchEnabled` cycle completely broken)**: Three interdependent issues in the `enabled` setter and `touchEnabled` accessor:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
429
|
+
1. **`touchEnabled` getter always returned `undefined`**. Overriding only the setter on `Component.prototype` creates a JS accessor with `get: undefined`, which shadows the inherited `DisplayObject` getter. Every read of `.touchEnabled` on any Component subclass (Button, Label, TextInput, …) silently returned `undefined` instead of the real boolean.
|
|
430
|
+
2. **`enabled = false` never disabled hit-testing**. The setter delegated to `this.touchEnabled = false`, but `Component`'s own `touchEnabled` setter contains a guard (`if (this._enabled) super.touchEnabled = value`) that skips the display-level write when the component is already disabled. The result: a disabled button still captured touches and blocked elements behind it — unlike egret, where disabled components are excluded from hit-testing.
|
|
431
|
+
3. **disable → enable permanently broke touch**. The disable path clobbered `_explicitTouchEnabled` to `false`, and the re-enable path restored `$touchEnabled` from that corrupted value — leaving every Component subclass permanently non-touchable after a single disable/enable cycle.
|
|
432
|
+
The fix matches egret's `$setEnabled`: the `enabled` setter now writes `touchEnabled` / `touchChildren` directly at the display-object level via `super.touchEnabled` / `super.touchChildren`, bypassing the guarded setters. Additionally, `touchEnabled` and `touchChildren` getters are now explicitly overridden to delegate to `super`, un-shadowing the parent accessor.
|
|
361
433
|
- **Skin factory: ES class constructors crash via `.call(this)`**: 1.0.4 fixed the EXML binding `this` context by switching from `new factory()` to `factory.call(this)`, but `call()` throws `TypeError` on genuine ES class constructors (the documented `skinName: (new () => Skin)` path). Now detects class constructors via `Function.prototype.toString()` and falls back to `new`.
|
|
362
434
|
- **Button: `selected` PropertyEvent never dispatched**: `selected` setter did not dispatch `PropertyEvent('selected')`, breaking data bindings (`{selected}`) on Buttons and ToggleButtons. Now dispatched after `_selected` is updated.
|
|
363
435
|
- **Button: redundant `touchEnabled` override after `enabled` setter fix**: The now-fixed `Component.enabled` setter handles `touchEnabled`/`touchChildren` at the display-object level. Button's own `this.touchEnabled = value` line was overwriting that with the user's new value regardless of pre-disable intent, so it has been removed.
|
|
@@ -380,7 +452,7 @@ protected override onSkinRemoved(): void {
|
|
|
380
452
|
- **Scroller (viewport orphaned on skin re-apply)**: Egret overrides `setSkin` to re-`addChildAt(viewport, 0)` after the skin (scroll bars) is applied so the viewport is never orphaned and sits beneath the bars. Kurot was missing this override; now added.
|
|
381
453
|
- **Scroller (static-object field)**: `private static readonly _vpBounds = new Rectangle()` was converted to a module-level constant, applying the same remedy as the HSlider/VSlider class-name-corruption fix from 1.0.3.
|
|
382
454
|
- **ItemRenderer (labelDisplay auto-sync)**: Added `partAdded`/`partRemoved`/`dataChanged` to auto-sync `labelDisplay.text = String(data)`, matching Egret's binding fallback. Previously the default ItemRenderer had no mechanism to push `data` into the label.
|
|
383
|
-
- **Label (_widthConstraint)**: Added `_widthConstraint` mechanism (`setLayoutBoundsSize` override + `measure` update) so that when a parent layout constrains the Label's width, the measured height correctly accounts for text wrapping. Matches Egret's Label L695-710.
|
|
455
|
+
- **Label (\_widthConstraint)**: Added `_widthConstraint` mechanism (`setLayoutBoundsSize` override + `measure` update) so that when a parent layout constrains the Label's width, the measured height correctly accounts for text wrapping. Matches Egret's Label L695-710.
|
|
384
456
|
- **Label (text PropertyEvent)**: `text` setter now dispatches `PropertyEvent('text')` for data binding.
|
|
385
457
|
- **Panel (elementsContent)**: Added missing `elementsContent` setter so that EXML-declared children of `<eui:Panel>` are added to the display list. Previously they were silently discarded because Panel (via Component) had no such setter.
|
|
386
458
|
- **Panel (drag includeInLayout)**: Dragging the moveArea now sets `includeInLayout = false` to prevent the parent layout from snapping the panel back.
|
package/README.md
CHANGED
|
@@ -2,22 +2,75 @@
|
|
|
2
2
|
|
|
3
3
|
UI component framework for [@kurot/core](https://github.com/kurot-engine/kurot/tree/main/packages/core). Migrated from Egret EUI, rewritten in modern TypeScript with clean class inheritance — no namespace hacks, no prototype manipulation.
|
|
4
4
|
|
|
5
|
-
> **
|
|
5
|
+
> **Package version: 3.2.0.** Requires `@kurot/core@^2.2.0`. Targets ES2022 + evergreen browsers, same as core.
|
|
6
6
|
|
|
7
7
|
For the full list of changes in this release, see [CHANGELOG.md](./CHANGELOG.md).
|
|
8
8
|
|
|
9
|
+
## Label text fitting in 3.1.0
|
|
10
|
+
|
|
11
|
+
Single-line Labels can shrink their drawing size to fit the available region:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Label } from '@kurot/ui';
|
|
15
|
+
|
|
16
|
+
const amount = new Label('KZT 10 000,00');
|
|
17
|
+
amount.width = 140;
|
|
18
|
+
amount.size = 24;
|
|
19
|
+
amount.multiline = false;
|
|
20
|
+
amount.textFit = 'shrink';
|
|
21
|
+
amount.minFontSize = 16;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`size` stays authored; `renderedSize` and `textFitOverflow` are read-only results
|
|
25
|
+
after layout validation. Shorter text or larger bounds restore the base size.
|
|
26
|
+
Put a Button's fitting policy on its `labelDisplay` skin part, so icon spacing
|
|
27
|
+
and state overrides are respected. EditableText rejects shrinking; multiline
|
|
28
|
+
Labels retain their base size.
|
|
29
|
+
|
|
30
|
+
Label defaults to multiline, while explicit `multiline = false` displays one
|
|
31
|
+
unwrapped first line. Remove an old false flag or set it to true for text
|
|
32
|
+
intended to wrap. Files are not migrated automatically. Load fonts before
|
|
33
|
+
measurement; after late loading, call `label.invalidateSize()` to refresh
|
|
34
|
+
metrics even if the family name is unchanged.
|
|
35
|
+
|
|
36
|
+
See the [text layout and fitting contract](docs/label-text-layout.md). Fitting
|
|
37
|
+
metadata was introduced in ui-document 0.9.0 and remains supported in 0.11.0.
|
|
38
|
+
Current CLI-built KUI projects use published CLI 3.3.0 with ui-document `^0.11.0`;
|
|
39
|
+
Published ui-runtime 0.8.2 uses the same kernel range. Programmatic UI depends
|
|
40
|
+
only on Core.
|
|
41
|
+
|
|
9
42
|
## Installation
|
|
10
43
|
|
|
11
44
|
```bash
|
|
12
|
-
pnpm add @kurot/ui @kurot/core
|
|
45
|
+
pnpm add @kurot/ui@^3.2.0 @kurot/core@^2.2.0
|
|
13
46
|
```
|
|
14
47
|
|
|
15
48
|
`@kurot/ui` declares `@kurot/core` as a peer dependency. Install both packages explicitly so the application controls the resolved core version.
|
|
16
49
|
|
|
17
|
-
|
|
50
|
+
UI 3.2 requires Core 2.2.0 or later within Core 2.x for BitmapText rendering and
|
|
51
|
+
font resources. Core installs its published bitmap-font dependency automatically.
|
|
52
|
+
Refresh older Core/UI lockfiles and old sheet manifests with
|
|
18
53
|
string-valued `subkeys` in Kurot Editor before launching the application.
|
|
19
54
|
See the [resource migration guide](../ui-document/docs/resource-nine-slice.md).
|
|
20
55
|
|
|
56
|
+
## Project style colors
|
|
57
|
+
|
|
58
|
+
CLI 3.3.0 resolves Label presets and named colors from the optional
|
|
59
|
+
`resource/config/style.json` into native UI properties, including state overrides:
|
|
60
|
+
|
|
61
|
+
```xml
|
|
62
|
+
<Label id="labelDisplay" textColor="#FF9900"
|
|
63
|
+
textColor.disabled="@style:colors:disabled-text" />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The Label belongs to a Skin declaring the `disabled` state. Native Skin state
|
|
67
|
+
handling applies the compiled numeric color and restores the base color on
|
|
68
|
+
leaving that state. The same reference syntax works for base color properties.
|
|
69
|
+
UI does not read style.json or evaluate XML references itself; programmatic
|
|
70
|
+
components assign numeric colors. This release does not introduce complete
|
|
71
|
+
typography presets or automatic live theme switching. See the
|
|
72
|
+
[project style contract](../ui-document/docs/project-styles.md).
|
|
73
|
+
|
|
21
74
|
## Quick Start
|
|
22
75
|
|
|
23
76
|
```ts
|
|
@@ -98,11 +151,7 @@ class MyButtonSkin extends Skin {
|
|
|
98
151
|
this.bg = new Rect(120, 36, 0x6c5ce7);
|
|
99
152
|
this.skinParts = ['bg'];
|
|
100
153
|
this.elementsContent = [this.bg];
|
|
101
|
-
this.states = [
|
|
102
|
-
new State('up'),
|
|
103
|
-
new State('down', [new SetProperty('bg', 'fillColor', 0x5a4bd1)]),
|
|
104
|
-
new State('disabled', [new SetProperty('bg', 'fillColor', 0x636e72)]),
|
|
105
|
-
];
|
|
154
|
+
this.states = [new State('up'), new State('down', [new SetProperty('bg', 'fillColor', 0x5a4bd1)]), new State('disabled', [new SetProperty('bg', 'fillColor', 0x636e72)])];
|
|
106
155
|
}
|
|
107
156
|
}
|
|
108
157
|
|
|
@@ -134,18 +183,12 @@ export class ConfirmPanel extends Component {
|
|
|
134
183
|
|
|
135
184
|
protected override onSkinReady(): void {
|
|
136
185
|
super.onSkinReady();
|
|
137
|
-
this.skinParts.btnConfirm.addEventListener(
|
|
138
|
-
TouchEvent.TOUCH_TAP,
|
|
139
|
-
this.onConfirm,
|
|
140
|
-
);
|
|
186
|
+
this.skinParts.btnConfirm.addEventListener(TouchEvent.TOUCH_TAP, this.onConfirm);
|
|
141
187
|
this.skinParts.lblMessage.text = 'Continue?';
|
|
142
188
|
}
|
|
143
189
|
|
|
144
190
|
protected override onSkinRemoved(): void {
|
|
145
|
-
this.skinParts.btnConfirm.removeEventListener(
|
|
146
|
-
TouchEvent.TOUCH_TAP,
|
|
147
|
-
this.onConfirm,
|
|
148
|
-
);
|
|
191
|
+
this.skinParts.btnConfirm.removeEventListener(TouchEvent.TOUCH_TAP, this.onConfirm);
|
|
149
192
|
super.onSkinRemoved();
|
|
150
193
|
}
|
|
151
194
|
|
|
@@ -179,19 +222,20 @@ dynamic properties; use `this.skinParts.<name>` during the ready lifecycle.
|
|
|
179
222
|
|
|
180
223
|
### Basic Controls
|
|
181
224
|
|
|
182
|
-
| Component | Description
|
|
183
|
-
| -------------- |
|
|
184
|
-
| `Label` | Text display. Wraps `TextField` in the UI lifecycle.
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
225
|
+
| Component | Description |
|
|
226
|
+
| -------------- | ------------------------------------------------------------------------------- |
|
|
227
|
+
| `Label` | Text display. Wraps `TextField` in the UI lifecycle. |
|
|
228
|
+
| `BitmapLabel` | Bitmap-font display. Wraps BitmapText with font resources, layout and bindings. |
|
|
229
|
+
| `Button` | Tappable button with `up`/`down`/`disabled` states and `labelDisplay` part. |
|
|
230
|
+
| `CheckBox` | Toggle button. Dispatches `Event.CHANGE` on selection change. |
|
|
231
|
+
| `RadioButton` | Mutually exclusive toggle. Use `groupName` to link buttons. |
|
|
232
|
+
| `ToggleButton` | Base for toggle-style buttons. |
|
|
233
|
+
| `ToggleSwitch` | Binary on/off switch (visual variant of `ToggleButton`). |
|
|
234
|
+
| `ProgressBar` | Value indicator. Inject `thumb` (a `Component`) as the fill part. |
|
|
235
|
+
| `HSlider` | Horizontal slider. Inject `thumb` and `track` skin parts; default range 0–100. |
|
|
236
|
+
| `VSlider` | Vertical slider. Inject `thumb` and `track` skin parts; default range 0–100. |
|
|
237
|
+
| `Rect` | Filled/stroked rectangle. Supports `fillColor`, `strokeColor`, `fillAlpha`. |
|
|
238
|
+
| `Image` | Bitmap display. Supports URL string or `Texture`, `scale9Grid`, `fillMode`. |
|
|
195
239
|
|
|
196
240
|
Both sliders inherit Range's default `minimum = 0` and `maximum = 100`.
|
|
197
241
|
Set either bound explicitly when a control needs a different range.
|
|
@@ -221,13 +265,13 @@ gesture. Set `visible="true" autoVisibility="false"` to keep a bar visible.
|
|
|
221
265
|
|
|
222
266
|
### Data-Driven
|
|
223
267
|
|
|
224
|
-
| Component | Description
|
|
225
|
-
| -------------- |
|
|
226
|
-
| `DataGroup` | Renders a data collection using item renderers. Supports virtual layout for large datasets.
|
|
227
|
-
| `List` | `DataGroup` with tap-to-select. Dispatches `ItemTapEvent.ITEM_TAP`.
|
|
228
|
-
| `TabBar` | Horizontal tab strip driven by `dataProvider`. Dispatches `ItemTapEvent.ITEM_TAP`.
|
|
268
|
+
| Component | Description |
|
|
269
|
+
| -------------- | ----------------------------------------------------------------------------------------------- |
|
|
270
|
+
| `DataGroup` | Renders a data collection using item renderers. Supports virtual layout for large datasets. |
|
|
271
|
+
| `List` | `DataGroup` with tap-to-select. Dispatches `ItemTapEvent.ITEM_TAP`. |
|
|
272
|
+
| `TabBar` | Horizontal tab strip driven by `dataProvider`. Dispatches `ItemTapEvent.ITEM_TAP`. |
|
|
229
273
|
| `ComboBox` | Drop-down selector. Tapping toggles a `list` skin part; dispatches `Event.CHANGE` on selection. |
|
|
230
|
-
| `ItemRenderer` | Base class for custom item renderers. Override `dataChanged()` to update visuals.
|
|
274
|
+
| `ItemRenderer` | Base class for custom item renderers. Override `dataChanged()` to update visuals. |
|
|
231
275
|
|
|
232
276
|
### Scroll Bars
|
|
233
277
|
|
|
@@ -256,10 +300,12 @@ data.addItem('Durian');
|
|
|
256
300
|
data.addItemAt('Elderberry', 1);
|
|
257
301
|
data.removeItemAt(0);
|
|
258
302
|
data.replaceItemAt('Fig', 0);
|
|
259
|
-
data.
|
|
260
|
-
data.sort((a, b) => (a > b ? 1 : -1)); // custom sort
|
|
303
|
+
data.sort((a, b) => String(a).localeCompare(String(b)));
|
|
261
304
|
data.filterFunction(item => item !== 'Fig');
|
|
262
305
|
data.refresh(); // notify view after manual source changes
|
|
306
|
+
|
|
307
|
+
const records = new ArrayCollection([{ name: 'Pear' }, { name: 'Apple' }]);
|
|
308
|
+
records.sortOn('name'); // sort records by field
|
|
263
309
|
```
|
|
264
310
|
|
|
265
311
|
## Virtual Layout
|
|
@@ -310,29 +356,43 @@ component.percentHeight = 100;
|
|
|
310
356
|
## View States
|
|
311
357
|
|
|
312
358
|
```ts
|
|
313
|
-
import { State, SetProperty
|
|
359
|
+
import { Label, Rect, Skin, State, SetProperty } from '@kurot/ui';
|
|
314
360
|
|
|
315
|
-
class
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
new
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
361
|
+
class StatefulButtonSkin extends Skin {
|
|
362
|
+
constructor() {
|
|
363
|
+
super();
|
|
364
|
+
const bg = new Rect(120, 36, 0x6c5ce7);
|
|
365
|
+
const labelDisplay = new Label();
|
|
366
|
+
labelDisplay.textColor = 0xffffff;
|
|
367
|
+
labelDisplay.horizontalCenter = 0;
|
|
368
|
+
labelDisplay.verticalCenter = 0;
|
|
369
|
+
this.setPart('bg', bg);
|
|
370
|
+
this.setPart('labelDisplay', labelDisplay);
|
|
371
|
+
this.skinParts = ['labelDisplay'];
|
|
372
|
+
this.elementsContent = [bg, labelDisplay];
|
|
373
|
+
this.states = [
|
|
374
|
+
new State('up'),
|
|
375
|
+
new State('down', [new SetProperty('bg', 'fillColor', 0x5a4bd1)]),
|
|
376
|
+
new State('disabled', [new SetProperty('bg', 'fillColor', 0x636e72), new SetProperty('labelDisplay', 'textColor', 0xb2bec3)]),
|
|
377
|
+
];
|
|
378
|
+
}
|
|
324
379
|
}
|
|
325
380
|
```
|
|
326
381
|
|
|
382
|
+
Button selects `up`, `down` or `disabled` through its native behavior. Each
|
|
383
|
+
state restores the previous property values before applying the next overrides.
|
|
384
|
+
CLI-built skins generate the same `State`/`SetProperty` objects from XML
|
|
385
|
+
attributes such as `textColor.disabled`.
|
|
386
|
+
|
|
327
387
|
## Events
|
|
328
388
|
|
|
329
|
-
| Event | Dispatched by
|
|
330
|
-
| ----------------------------------- |
|
|
389
|
+
| Event | Dispatched by | Description |
|
|
390
|
+
| ----------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
331
391
|
| `Event.CHANGE` | `List`, `TabBar`, `ComboBox`, `CheckBox`, `RadioButton`, `Range` | Selection or value changed (user interaction only for List/TabBar) |
|
|
332
|
-
| `ItemTapEvent.ITEM_TAP` | `List`, `TabBar`
|
|
333
|
-
| `CollectionEvent.COLLECTION_CHANGE` | `ArrayCollection`
|
|
334
|
-
| `UIEvent.CLOSING` | `Panel`
|
|
335
|
-
| `UIEvent.CREATION_COMPLETE` | Any `Component`
|
|
392
|
+
| `ItemTapEvent.ITEM_TAP` | `List`, `TabBar` | Item tapped. Has `item`, `itemIndex`, `itemRenderer` |
|
|
393
|
+
| `CollectionEvent.COLLECTION_CHANGE` | `ArrayCollection` | Data added, removed, replaced, reset |
|
|
394
|
+
| `UIEvent.CLOSING` | `Panel` | Close button tapped (cancelable) |
|
|
395
|
+
| `UIEvent.CREATION_COMPLETE` | Any `Component` | First `createChildren` completed |
|
|
336
396
|
|
|
337
397
|
## UI Benchmark
|
|
338
398
|
|
|
@@ -347,11 +407,11 @@ report can distinguish a stable pool from per-frame renderer churn.
|
|
|
347
407
|
|
|
348
408
|
The first complete Chromium run used 60 warmup frames and 300 measured frames:
|
|
349
409
|
|
|
350
|
-
| Workload
|
|
351
|
-
|
|
|
352
|
-
| 400-node static image UI
|
|
353
|
-
| 240-node transform/alpha animation | 3.90 ms |
|
|
354
|
-
| 10,000-record virtual list
|
|
410
|
+
| Workload | Setup | Frame P95 | Render P95 | Draw calls | UI lifecycle result |
|
|
411
|
+
| ---------------------------------- | ------: | --------: | ---------: | ---------: | ------------------------------------------ |
|
|
412
|
+
| 400-node static image UI | 8.50 ms | 10.20 ms | 0.20 ms | 1 | No repeated validation after stabilization |
|
|
413
|
+
| 240-node transform/alpha animation | 3.90 ms | 10.00 ms | 0.30 ms | 1 | No measure or display-list validation |
|
|
414
|
+
| 10,000-record virtual list | 6.90 ms | 9.90 ms | 0.50 ms | 5 | 19 renderers created and at most 19 live |
|
|
355
415
|
|
|
356
416
|
The transform workload recorded 72,000 `commitProperties` calls: 240 moving UI
|
|
357
417
|
nodes × 300 measured frames. Multiple property changes on the same component
|
|
@@ -380,14 +440,39 @@ cross-framework ranking.
|
|
|
380
440
|
|
|
381
441
|
## Differences from Egret EUI
|
|
382
442
|
|
|
383
|
-
| | Egret EUI | @kurot/ui
|
|
384
|
-
| -------------- | --------------------------- |
|
|
385
|
-
| Namespace | `eui.*` global | ES Module named exports
|
|
386
|
-
| Component base | `namespace` + `mixin` | Standard class inheritance
|
|
387
|
-
| Layout state | Prototype-injected | `UIState` delegation
|
|
388
|
-
| Authored skins | EXML runtime parser
|
|
389
|
-
| Skin parts | Incremental dynamic fields | Atomic typed `skinParts`
|
|
390
|
-
| Skin lifecycle | `partAdded` / `partRemoved` | `onSkinReady` / `onSkinRemoved`
|
|
391
|
-
| `thisObject` | Required in event listeners | Not needed — use arrow functions
|
|
392
|
-
| Virtual layout | Default on | Opt-in via `useVirtualLayout = true`
|
|
393
|
-
| i18n | Built-in |
|
|
443
|
+
| | Egret EUI | @kurot/ui |
|
|
444
|
+
| -------------- | --------------------------- | ----------------------------------------------------------- |
|
|
445
|
+
| Namespace | `eui.*` global | ES Module named exports |
|
|
446
|
+
| Component base | `namespace` + `mixin` | Standard class inheritance |
|
|
447
|
+
| Layout state | Prototype-injected | `UIState` delegation |
|
|
448
|
+
| Authored skins | EXML runtime parser | KUI XML compiled by `@kurot/cli` |
|
|
449
|
+
| Skin parts | Incremental dynamic fields | Atomic typed `skinParts` |
|
|
450
|
+
| Skin lifecycle | `partAdded` / `partRemoved` | `onSkinReady` / `onSkinRemoved` |
|
|
451
|
+
| `thisObject` | Required in event listeners | Not needed — use arrow functions |
|
|
452
|
+
| Virtual layout | Default on | Opt-in via `useVirtualLayout = true` |
|
|
453
|
+
| i18n | Built-in | Project-managed translations; Core handles Unicode wrapping |
|
|
454
|
+
|
|
455
|
+
## Bitmap labels in 3.2.0
|
|
456
|
+
|
|
457
|
+
[BitmapLabel](docs/bitmap-label.md) wraps Core BitmapText with native UI layout,
|
|
458
|
+
spacing, alignment and configured font-resource names:
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
import { BitmapLabel } from '@kurot/ui';
|
|
462
|
+
|
|
463
|
+
const amount = new BitmapLabel('1,234.56');
|
|
464
|
+
amount.font = 'number_font_fnt';
|
|
465
|
+
amount.multiline = false;
|
|
466
|
+
amount.height = 100;
|
|
467
|
+
group.addChild(amount);
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Register the font descriptor in Core's resource configuration before assigning
|
|
471
|
+
its name, or assign a BitmapFont directly. The label borrows its font; the
|
|
472
|
+
resource cache or caller retains ownership. Superseded async requests cannot
|
|
473
|
+
replace a newer assignment. Successful named loads dispatch Event.COMPLETE;
|
|
474
|
+
failed or incorrectly typed resources dispatch IOErrorEvent.IO_ERROR.
|
|
475
|
+
|
|
476
|
+
The component supports native code and programmatic skins. Installed KUI
|
|
477
|
+
compilers, the ui-document catalog, Editor and ui-runtime materializers do not
|
|
478
|
+
yet adopt the BitmapLabel tag. Published UI 3.1.0 does not include the component.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BitmapFont } from '@kurot/core';
|
|
2
|
+
import { Component } from './Component.js';
|
|
3
|
+
import type { IDisplayText } from '../core/IDisplayText.js';
|
|
4
|
+
/**
|
|
5
|
+
* UI layout wrapper around BitmapText. String fonts are configured resource
|
|
6
|
+
* names; FontAnalyzer loads the descriptor and its page. Font ownership stays
|
|
7
|
+
* with the resource cache or the caller that supplied a BitmapFont.
|
|
8
|
+
*/
|
|
9
|
+
export declare class BitmapLabel extends Component implements IDisplayText {
|
|
10
|
+
private readonly _bitmapText;
|
|
11
|
+
private _font?;
|
|
12
|
+
private _fontChanged;
|
|
13
|
+
private _fontRequest;
|
|
14
|
+
private _widthConstraint;
|
|
15
|
+
constructor(text?: string);
|
|
16
|
+
get text(): string;
|
|
17
|
+
set text(value: string);
|
|
18
|
+
get font(): string | BitmapFont | undefined;
|
|
19
|
+
set font(value: string | BitmapFont | undefined);
|
|
20
|
+
get textAlign(): 'left' | 'center' | 'right';
|
|
21
|
+
set textAlign(value: 'left' | 'center' | 'right');
|
|
22
|
+
get verticalAlign(): 'top' | 'middle' | 'bottom';
|
|
23
|
+
set verticalAlign(value: 'top' | 'middle' | 'bottom');
|
|
24
|
+
get letterSpacing(): number;
|
|
25
|
+
set letterSpacing(value: number);
|
|
26
|
+
get lineSpacing(): number;
|
|
27
|
+
set lineSpacing(value: number);
|
|
28
|
+
get multiline(): boolean;
|
|
29
|
+
set multiline(value: boolean);
|
|
30
|
+
get smoothing(): boolean;
|
|
31
|
+
set smoothing(value: boolean);
|
|
32
|
+
/**
|
|
33
|
+
* Content metrics under the label's width constraint, before height clipping.
|
|
34
|
+
*/
|
|
35
|
+
get textWidth(): number;
|
|
36
|
+
get textHeight(): number;
|
|
37
|
+
createChildren(): void;
|
|
38
|
+
commitProperties(): void;
|
|
39
|
+
measure(): void;
|
|
40
|
+
setLayoutBoundsSize(layoutWidth: number, layoutHeight: number): void;
|
|
41
|
+
updateDisplayList(unscaledWidth: number, unscaledHeight: number): void;
|
|
42
|
+
private _invalidateText;
|
|
43
|
+
private _measureText;
|
|
44
|
+
private _resolveFont;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=BitmapLabel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BitmapLabel.d.ts","sourceRoot":"","sources":["../../../src/kurot/components/BitmapLabel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,SAAU,YAAW,YAAY;IAEjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,KAAK,CAAC,CAAsB;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAO;gBAGZ,IAAI,SAAK;IAO5B,IAAW,IAAI,IAAI,MAAM,CAExB;IACD,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,EAK5B;IACD,IAAW,IAAI,IAAI,MAAM,GAAG,UAAU,GAAG,SAAS,CAEjD;IACD,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,EAQrD;IACD,IAAW,SAAS,IAAI,MAAM,GAAG,QAAQ,GAAG,OAAO,CAElD;IACD,IAAW,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,EAItD;IACD,IAAW,aAAa,IAAI,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAEtD;IACD,IAAW,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,EAI1D;IACD,IAAW,aAAa,IAAI,MAAM,CAEjC;IACD,IAAW,aAAa,CAAC,KAAK,EAAE,MAAM,EAIrC;IACD,IAAW,WAAW,IAAI,MAAM,CAE/B;IACD,IAAW,WAAW,CAAC,KAAK,EAAE,MAAM,EAInC;IACD,IAAW,SAAS,IAAI,OAAO,CAE9B;IACD,IAAW,SAAS,CAAC,KAAK,EAAE,OAAO,EAIlC;IACD,IAAW,SAAS,IAAI,OAAO,CAE9B;IACD,IAAW,SAAS,CAAC,KAAK,EAAE,OAAO,EAIlC;IACD;;OAEG;IACH,IAAW,SAAS,IAAI,MAAM,CAE7B;IACD,IAAW,UAAU,IAAI,MAAM,CAE9B;IAGe,cAAc,IAAI,IAAI;IAItB,gBAAgB,IAAI,IAAI;IAMxB,OAAO,IAAI,IAAI;IAIf,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAOpE,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI;IAOtF,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,YAAY;CA0BpB"}
|