@jimka/typescript-ui 0.1.0 → 0.1.1
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 +5 -18
- package/dist/lib/AbstractBooleanInput-C6CidMMX.js +2 -0
- package/dist/lib/AbstractBooleanInput-C6CidMMX.js.map +1 -0
- package/dist/lib/AbstractInput-CfjW_HM2.js +2 -0
- package/dist/lib/AbstractInput-CfjW_HM2.js.map +1 -0
- package/dist/lib/AnimatedDropdown-BFz-DO7R.js +2 -0
- package/dist/lib/AnimatedDropdown-BFz-DO7R.js.map +1 -0
- package/dist/lib/Border-5Ki2DCWz.js +2 -0
- package/dist/lib/Border-5Ki2DCWz.js.map +1 -0
- package/dist/lib/BoxLayout-8ryMD4j5.js +2 -0
- package/dist/lib/BoxLayout-8ryMD4j5.js.map +1 -0
- package/dist/lib/Button-Cdq2ySPL.js +2 -0
- package/dist/lib/Button-Cdq2ySPL.js.map +1 -0
- package/dist/lib/Card-AKIUAWYS.js +2 -0
- package/dist/lib/Card-AKIUAWYS.js.map +1 -0
- package/dist/lib/ComboBox-e_YVsWBr.js +2 -0
- package/dist/lib/ComboBox-e_YVsWBr.js.map +1 -0
- package/dist/lib/Component-Bs6TvaGZ.js +2 -0
- package/dist/lib/Component-Bs6TvaGZ.js.map +1 -0
- package/dist/lib/Container-CzyZeMyZ.js +2 -0
- package/dist/lib/Container-CzyZeMyZ.js.map +1 -0
- package/dist/lib/DOM-DeF_dWe2.js +2 -0
- package/dist/lib/DOM-DeF_dWe2.js.map +1 -0
- package/dist/lib/DragManager-c6M_mE3e.js +2 -0
- package/dist/lib/DragManager-c6M_mE3e.js.map +1 -0
- package/dist/lib/FieldDecorator-Bl0h9UEF.js +2 -0
- package/dist/lib/FieldDecorator-Bl0h9UEF.js.map +1 -0
- package/dist/lib/Fit-CUS1JXy3.js +2 -0
- package/dist/lib/Fit-CUS1JXy3.js.map +1 -0
- package/dist/lib/Glyph-6Ki3A1_a.js +2 -0
- package/dist/lib/Glyph-6Ki3A1_a.js.map +1 -0
- package/dist/lib/Grid-D8luwRPI.js +2 -0
- package/dist/lib/Grid-D8luwRPI.js.map +1 -0
- package/dist/lib/GridConstraints-CzC0w4i-.js +2 -0
- package/dist/lib/GridConstraints-CzC0w4i-.js.map +1 -0
- package/dist/lib/HBox-BWMf9h6r.js +2 -0
- package/dist/lib/HBox-BWMf9h6r.js.map +1 -0
- package/dist/lib/Header-CQjomjo0.js +2 -0
- package/dist/lib/Header-CQjomjo0.js.map +1 -0
- package/dist/lib/IconText-BXJK0MOq.js +2 -0
- package/dist/lib/IconText-BXJK0MOq.js.map +1 -0
- package/dist/lib/LayoutSerialization-C_zcwaN3.js +2 -0
- package/dist/lib/LayoutSerialization-C_zcwaN3.js.map +1 -0
- package/dist/lib/LayoutSizes-XdhpAOmc.js +2 -0
- package/dist/lib/LayoutSizes-XdhpAOmc.js.map +1 -0
- package/dist/lib/List-BgxnLWnl.js +2 -0
- package/dist/lib/List-BgxnLWnl.js.map +1 -0
- package/dist/lib/Menu-BdnwRY0M.js +2 -0
- package/dist/lib/Menu-BdnwRY0M.js.map +1 -0
- package/dist/lib/MenuButton-D15cSbMf.js +2 -0
- package/dist/lib/MenuButton-D15cSbMf.js.map +1 -0
- package/dist/lib/Panel-DApa7vA6.js +2 -0
- package/dist/lib/Panel-DApa7vA6.js.map +1 -0
- package/dist/lib/Position-DJKB0N3l.js +2 -0
- package/dist/lib/Position-DJKB0N3l.js.map +1 -0
- package/dist/lib/ProgressSpinner-CNYcsBhw.js +2 -0
- package/dist/lib/ProgressSpinner-CNYcsBhw.js.map +1 -0
- package/dist/lib/RadioButton-CepkneSA.js +2 -0
- package/dist/lib/RadioButton-CepkneSA.js.map +1 -0
- package/dist/lib/RovingTabIndex-D-zOuptw.js +2 -0
- package/dist/lib/RovingTabIndex-D-zOuptw.js.map +1 -0
- package/dist/lib/Scrollbar-DQdCdj94.js +2 -0
- package/dist/lib/Scrollbar-DQdCdj94.js.map +1 -0
- package/dist/lib/Slider-DvDdVvRm.js +2 -0
- package/dist/lib/Slider-DvDdVvRm.js.map +1 -0
- package/dist/lib/Spacer-BqiPiCqz.js +2 -0
- package/dist/lib/Spacer-BqiPiCqz.js.map +1 -0
- package/dist/lib/TabButton-DqYDfN7P.js +2 -0
- package/dist/lib/TabButton-DqYDfN7P.js.map +1 -0
- package/dist/lib/Text-DJoUHukb.js +2 -0
- package/dist/lib/Text-DJoUHukb.js.map +1 -0
- package/dist/lib/Tooltip-5BR7yYEX.js +3 -0
- package/dist/lib/Tooltip-5BR7yYEX.js.map +1 -0
- package/dist/lib/VBox-CdV9VGxR.js +2 -0
- package/dist/lib/VBox-CdV9VGxR.js.map +1 -0
- package/dist/lib/VirtualRowView-C18j90n5.js +2 -0
- package/dist/lib/VirtualRowView-C18j90n5.js.map +1 -0
- package/dist/lib/VirtualScroller-BKMvTisA.js +2 -0
- package/dist/lib/VirtualScroller-BKMvTisA.js.map +1 -0
- package/dist/lib/component/button.es.js +1 -1
- package/dist/lib/component/button.es.js.map +1 -1
- package/dist/lib/component/chart.es.js +1 -1
- package/dist/lib/component/chart.es.js.map +1 -1
- package/dist/lib/component/container.es.js +1 -1
- package/dist/lib/component/container.es.js.map +1 -1
- package/dist/lib/component/diagram.es.js +1 -1
- package/dist/lib/component/diagram.es.js.map +1 -1
- package/dist/lib/component/display.es.js +1 -1
- package/dist/lib/component/display.es.js.map +1 -1
- package/dist/lib/component/editor.es.js +3 -1
- package/dist/lib/component/editor.es.js.map +1 -1
- package/dist/lib/component/input.es.js +1 -1
- package/dist/lib/component/input.es.js.map +1 -1
- package/dist/lib/component/list.es.js +1 -1
- package/dist/lib/component/list.es.js.map +1 -1
- package/dist/lib/component/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +2 -2
- package/dist/lib/component/table.es.js.map +1 -1
- package/dist/lib/component/tree.es.js +1 -1
- package/dist/lib/component/tree.es.js.map +1 -1
- package/dist/lib/core.es.js +1 -1
- package/dist/lib/core.es.js.map +1 -1
- package/dist/lib/layout.es.js +1 -1
- package/dist/lib/overlay.es.js +1 -1
- package/dist/lib/overlay.es.js.map +1 -1
- package/dist/lib/primitive.es.js +1 -1
- package/dist/lib/router.es.js +2 -0
- package/dist/lib/router.es.js.map +1 -0
- package/dist/lib/types/component/container/SplitGutter.d.ts +1 -1
- package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
- package/dist/lib/types/component/display/Markdown.d.ts +10 -0
- package/dist/lib/types/component/display/index.d.ts +1 -1
- package/dist/lib/types/component/editor/MarkdownEditor.d.ts +6 -0
- package/dist/lib/types/component/editor/markdownTableTransformer.d.ts +2 -0
- package/dist/lib/types/core/DOM.d.ts +6 -0
- package/dist/lib/types/overlay/AbstractWindow.d.ts +1 -1
- package/dist/lib/types/router/RoutePattern.d.ts +18 -0
- package/dist/lib/types/router/Router.d.ts +36 -0
- package/dist/lib/types/router/index.d.ts +2 -0
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +8 -4
- package/package.json +6 -1
package/dist/lib/core.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.es.js","names":[],"sources":["../../src/typescript/lib/core/themes/ClassicTheme.ts","../../src/typescript/lib/core/themes/DarkTheme.ts","../../src/typescript/lib/core/Form.ts","../../src/typescript/lib/core/Body.ts","../../src/typescript/lib/core/FocusHistory.ts","../../src/typescript/lib/core/Binding.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Classic light theme using white backgrounds, black text, and gradient\n * buttons. The original default look, retained as an opt-in alternative now\n * that {@link ModernTheme} is the preselected theme.\n *\n * Authored as `defineTheme(BaseTheme, …)`: it declares only its palette (and\n * `colorScheme`); every structural token is inherited from {@link BaseTheme}.\n * Classic carries no structural override — its `tab.underBorderFullWidth`\n * already matches the base value.\n *\n * @category Theme\n */\nexport const ClassicTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'light',\n text : { color: 'rgb(0, 0, 0)' },\n body : { background: 'rgb(255, 255, 255)' },\n border : { color: 'black' },\n button : {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : 'rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n description: {\n foreground: 'rgb(110, 110, 110)',\n },\n pressed : {\n foreground: 'rgb(150, 150, 150)',\n background: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.30)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.25)',\n },\n flat : {\n hover : {\n background: 'rgba(0, 0, 0, 0.06)',\n border : '1px solid rgb(200, 200, 200)',\n },\n pressed: {\n background: 'rgba(0, 0, 0, 0.10)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.25)',\n border : '1px solid rgb(180, 180, 180)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(200, 200, 200)',\n shadow : '2px 2px 1px inset grey',\n },\n },\n input : {\n background : 'rgb(255, 255, 255)',\n border : '1px solid rgb(160, 160, 160)',\n borderHover: '1px solid rgb(120, 120, 120)',\n },\n form : {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(160, 160, 160)',\n color : 'rgb(40, 40, 40)',\n disabledBackground: 'rgb(240, 240, 240)',\n disabledColor : 'rgb(170, 170, 170)',\n focusRing : 'rgb(30, 100, 200)',\n toggle : {\n trackOffBackground: 'rgb(200, 200, 200)',\n trackOnBackground : 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n slider : {\n trackBackground : 'rgb(220, 220, 220)',\n trackActiveBackground: 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n checkbox: {\n background : 'rgb(255, 255, 255)',\n selectedBackground : 'rgb(30, 100, 200)',\n indeterminateBackground: 'rgb(160, 160, 160)',\n checkColor : 'rgb(255, 255, 255)',\n },\n radio : {\n background : 'rgb(255, 255, 255)',\n selectedBackground: 'rgb(30, 100, 200)',\n dotColor : 'rgb(255, 255, 255)',\n },\n },\n gutter: { background: '#AAAAAA' },\n collapse: {\n strip: { background: '#AAAAAA', size: '18px' },\n button: { color: 'rgb(100,100,100)' },\n },\n accordion: {\n border : '1px solid rgb(190,190,190)',\n header : {\n background: 'linear-gradient(rgb(230,230,230),rgb(210,210,210))',\n border : '1px solid rgb(190,190,190)',\n color : 'inherit',\n },\n panel : { border: 'rgb(210,210,210)' },\n indicator: { color: 'rgb(100,100,100)' },\n },\n tab : {\n toolbar: { background: '#eee', border: '#e1e1e8' },\n button : {\n background: 'linear-gradient(rgb(208, 208, 216), rgb(185, 185, 196))',\n border : 'none',\n hover : { background: 'linear-gradient(rgb(220, 220, 227), rgb(198, 198, 208))', border: 'none' },\n selected : { background: 'linear-gradient(rgb(255, 255, 255), rgb(235, 235, 240))', border: 'none' },\n },\n indicator: { color: '#1a73e8' },\n },\n window: {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.4)',\n snapGlow : '0 0 0 2px rgba(30, 100, 200, 0.7)',\n control : {\n background : 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : '1px solid rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n hoverBackground : 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n activeBackground: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n },\n header : { background: '#eee' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border: 'black',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.15)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.6)',\n new : 'rgba(70, 200, 70, 0.15)',\n dirty : 'rgba(255, 165, 0, 0.15)',\n stripe : 'rgba(0, 0, 0, 0.035)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(0, 0, 0, 0.04)',\n requiredEmptyOutlineColor : 'rgba(220, 60, 60, 0.6)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.6)',\n },\n resizeHandle: {\n color : 'rgba(0, 0, 0, 0.2)',\n },\n sortBadge: {\n background: 'rgba(0, 0, 0, 0.15)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(30, 100, 200, 0.10)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n },\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n statusBar: {\n background: 'rgb(245, 245, 245)',\n color : 'rgb(60, 60, 60)',\n border : 'rgb(220, 220, 220)',\n },\n toolBar: {\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n separatorColor: 'rgb(220, 220, 220)',\n },\n tooltip: {\n background: 'rgb(255, 255, 240)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(180, 180, 100)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.2)',\n },\n popover: {\n background: 'rgb(255, 255, 255)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.18)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n info : { background: 'rgba(210, 224, 244, 0.75)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(210, 240, 220, 0.75)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(248, 232, 204, 0.75)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(244, 214, 214, 0.75)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(200, 50, 50)',\n tooltip: {\n background: 'rgb(180, 30, 30)',\n color : 'rgb(255, 255, 255)',\n border : 'rgb(140, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0,0,0,0.15)',\n item: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n highlightBackground: 'rgba(30, 100, 200, 0.18)',\n highlightColor : 'inherit',\n disabledColor : 'rgb(170, 170, 170)',\n },\n },\n // Defaults mirror `autoComplete` numerically because both surfaces present\n // selectable rows; a theme that customises one gets the other matching\n // automatically. `row.separator` defaults to `transparent` so the visual\n // matches the prior native `<select>` (no row hairlines); themes can opt\n // in to a denser look by overriding to a `1px solid rgba(...)` colour.\n list: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n row: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.18)',\n selectedColor : 'inherit',\n focusRing : 'rgb(30, 100, 200)',\n disabledColor : 'rgb(170, 170, 170)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(30, 100, 200)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Picker tokens stay numerically in step with `autoComplete.item.*` — they\n // share the {@link PickerCell} class — so a theme that customises one\n // gets the other matching automatically.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(30, 100, 200, 0.08)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.45)' },\n border : 'rgb(220, 220, 220)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.35)',\n confirm : 'rgb(30, 180, 80)',\n cancel : 'rgb(200, 50, 50)',\n info : { background: 'rgba(30, 100, 200, 0.15)', foreground: 'rgb(30, 100, 200)' },\n affirm : { background: 'rgba(30, 180, 80, 0.15)', foreground: 'rgb(30, 180, 80)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.25)',\n border : 'rgb(220, 220, 220)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.18)',\n handle: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.16)',\n },\n },\n spinner: {\n dividerColor: 'rgb(180, 180, 180)',\n },\n progressBar: {\n track : { background: 'rgb(220, 220, 220)' },\n fill : { background: 'rgb(30, 100, 200)' },\n indeterminate: { background: 'rgb(30, 100, 200)' },\n },\n progressSpinner: {\n color : 'rgb(30, 100, 200)',\n backdrop: 'rgba(255, 255, 255, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(200, 200, 200, 0.9)',\n border : 'rgb(150, 150, 150)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.25)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.12)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.10)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(30, 100, 200)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : 'rgba(80, 140, 240, 0.40)',\n activeBackground : 'rgba(80, 140, 240, 0.28)',\n invalidBackground: 'rgba(200, 50, 50, 0.28)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.06)',\n border : '2px dashed rgba(80, 140, 240, 0.40)',\n activeBackground: 'rgba(80, 140, 240, 0.18)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.80)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito colour-blind-safe categorical palette, tuned for a light\n // background (Classic is a light scheme). Neutral grey axis/grid/label; the\n // selection ring reuses the theme's blue accent.\n chart: {\n series: [\n '#0072B2', // blue\n '#E69F00', // orange\n '#009E73', // green\n '#D55E00', // vermilion\n '#CC79A7', // purple\n '#56B4E9', // sky\n '#8C6D1F', // gold\n '#555555', // grey\n ],\n axis : 'rgb(120, 120, 120)',\n grid : 'rgb(220, 220, 220)',\n label : 'rgb(80, 80, 80)',\n selection: '#1a73e8',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Dark-mode theme using dark backgrounds and light text.\n *\n * Authored as `defineTheme(BaseTheme, …)`: beyond its palette and\n * `colorScheme: 'dark'`, its only structural divergence is\n * `tab.underBorderFullWidth: false` (the base value is `true`). Every other\n * structural token is inherited from {@link BaseTheme}.\n *\n * @category Theme\n */\nexport const DarkTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'dark',\n text : { color: 'rgb(220, 220, 220)' },\n body : { background: 'rgb(30, 30, 30)' },\n border : { color: 'rgb(90, 90, 90)' },\n button : {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border : 'rgb(80, 80, 80)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.5)',\n description: {\n foreground: 'rgb(160, 160, 160)',\n },\n pressed : {\n foreground: 'rgb(180, 180, 180)',\n background: 'linear-gradient(rgb(35, 35, 35), rgb(48, 48, 48))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.6)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(90, 90, 90), rgb(65, 65, 65))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.55)',\n },\n flat : {\n hover : {\n background: 'rgba(255, 255, 255, 0.08)',\n border : '1px solid rgb(90, 90, 90)',\n },\n pressed: {\n background: 'rgba(255, 255, 255, 0.12)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.55)',\n border : '1px solid rgb(70, 70, 70)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(35, 35, 35)',\n shadow : '2px 2px 1px inset #333',\n },\n },\n input : {\n background : 'rgb(40, 40, 40)',\n border : '1px solid rgb(110, 110, 110)',\n borderHover: '1px solid rgb(150, 150, 150)',\n },\n form : {\n background : 'rgb(40, 40, 40)',\n border : 'rgb(110, 110, 110)',\n color : 'rgb(230, 230, 230)',\n disabledBackground: 'rgb(60, 60, 60)',\n disabledColor : 'rgb(120, 120, 120)',\n focusRing : 'rgb(120, 170, 240)',\n toggle : {\n trackOffBackground: 'rgb(70, 70, 70)',\n trackOnBackground : 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n slider : {\n trackBackground : 'rgb(70, 70, 70)',\n trackActiveBackground: 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n checkbox: {\n background : 'rgb(40, 40, 40)',\n selectedBackground : 'rgb(120, 170, 240)',\n indeterminateBackground: 'rgb(100, 100, 100)',\n checkColor : 'rgb(20, 20, 20)',\n },\n radio : {\n background : 'rgb(40, 40, 40)',\n selectedBackground: 'rgb(120, 170, 240)',\n dotColor : 'rgb(20, 20, 20)',\n },\n },\n gutter: { background: '#555' },\n collapse: {\n strip: { background: '#555', size: '18px' },\n button: { color: 'rgb(160,160,160)' },\n },\n accordion: {\n border : '1px solid rgb(80,80,80)',\n header : {\n background: 'linear-gradient(rgb(60,60,60),rgb(45,45,45))',\n border : '1px solid rgb(80,80,80)',\n color : 'inherit',\n },\n panel : { border: 'rgb(70,70,70)' },\n indicator: { color: 'rgb(160,160,160)' },\n },\n tab : {\n underBorderFullWidth: false,\n toolbar: { background: '#2a2a2a', border: '#444' },\n button : {\n background: '#3a3a3a',\n border : 'none',\n hover : { background: '#454545', border: 'none' },\n selected : { background: 'rgb(30, 30, 30)', border: 'none' },\n },\n indicator: { color: '#4a9eff' },\n },\n window : {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.6)',\n snapGlow : '0 0 0 2px rgba(80, 150, 240, 0.8)',\n control : {\n background : 'rgb(30, 30, 30)',\n border : '1px solid transparent',\n shadow : 'none',\n hoverBackground : 'rgb(55, 55, 55)',\n activeBackground: 'rgb(45, 45, 45)',\n },\n header : { background: '#2a2a2a' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border: '#555',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.25)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.8)',\n new : 'rgba(70, 200, 70, 0.2)',\n dirty : 'rgba(255, 165, 0, 0.2)',\n stripe : 'rgba(255, 255, 255, 0.045)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(255, 255, 255, 0.04)',\n requiredEmptyOutlineColor : 'rgba(255, 90, 90, 0.8)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.8)',\n },\n resizeHandle: {\n color : 'rgba(255, 255, 255, 0.25)',\n },\n sortBadge: {\n background: 'rgba(255, 255, 255, 0.2)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(100, 140, 220, 0.15)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n },\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n statusBar: {\n background: 'rgb(45, 45, 45)',\n color : 'rgb(200, 200, 200)',\n border : 'rgb(70, 70, 70)',\n },\n toolBar: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n separatorColor: 'rgb(70, 70, 70)',\n },\n tooltip: {\n background: 'rgb(60, 60, 45)',\n color : 'rgb(220, 220, 180)',\n border : 'rgb(120, 110, 70)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.5)',\n },\n popover: {\n background: 'rgb(50, 50, 55)',\n color : 'rgb(230, 230, 235)',\n border : 'rgb(90, 90, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.55)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.4)',\n info : { background: 'rgba(30, 100, 200, 0.4)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(30, 180, 80, 0.4)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(220, 140, 0, 0.4)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(200, 50, 50, 0.4)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(220, 80, 80)',\n tooltip: {\n background: 'rgb(160, 30, 30)',\n color : 'rgb(255, 220, 220)',\n border : 'rgb(120, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0,0,0,0.5)',\n item: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n highlightBackground: 'rgba(100, 140, 220, 0.28)',\n highlightColor : 'rgb(220, 220, 255)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n },\n // Dark defaults track `autoComplete` for the same hover/selected hues so\n // the row chrome stays consistent across the two popover surfaces.\n list: {\n background: 'rgb(40, 40, 40)',\n border : 'rgb(80, 80, 80)',\n row: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n selectedBackground: 'rgba(100, 140, 220, 0.28)',\n selectedColor : 'rgb(220, 220, 255)',\n focusRing : 'rgb(120, 170, 240)',\n disabledColor : 'rgb(100, 100, 100)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(120, 170, 240)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Dark picker tokens follow the dark `autoComplete.item.*` hue family for\n // chevron-hover consistency with cell hover.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(120, 170, 255, 0.12)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.65)' },\n border : 'rgb(70, 70, 70)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.6)',\n confirm : 'rgb(80, 200, 110)',\n cancel : 'rgb(220, 90, 90)',\n info : { background: 'rgba(30, 100, 200, 0.25)', foreground: 'rgb(60, 130, 220)' },\n affirm : { background: 'rgba(80, 200, 110, 0.25)', foreground: 'rgb(80, 200, 110)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.55)',\n border : 'rgb(70, 70, 70)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(70, 70, 70)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.45)',\n handle: {\n hoverBackground : 'rgba(120, 170, 240, 0.12)',\n selectedBackground: 'rgba(120, 170, 240, 0.22)',\n },\n },\n spinner: {\n dividerColor: 'rgb(80, 80, 80)',\n },\n progressBar: {\n track : { background: 'rgb(55, 55, 55)' },\n fill : { background: 'rgb(60, 130, 220)' },\n indeterminate: { background: 'rgb(60, 130, 220)' },\n },\n progressSpinner: {\n color : 'rgb(60, 130, 220)',\n backdrop: 'rgba(20, 20, 20, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(60, 60, 60, 0.9)',\n border : 'rgb(100, 100, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.6)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.2)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.18)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(80, 140, 240)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.12)',\n border : 'rgba(80, 140, 240, 0.45)',\n activeBackground : 'rgba(80, 140, 240, 0.32)',\n invalidBackground: 'rgba(200, 50, 50, 0.32)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : '2px dashed rgba(80, 140, 240, 0.45)',\n activeBackground: 'rgba(80, 140, 240, 0.24)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.85)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito-derived categorical palette, brightened for adequate contrast on\n // a dark background. Light-grey axis/label with a dim grid; the selection\n // ring reuses the theme's blue accent (matching the focus indicator).\n chart: {\n series: [\n '#56B4E9', // sky\n '#E69F00', // orange\n '#00C08B', // green\n '#FF7F4D', // vermilion\n '#E48FC1', // purple\n '#0091D5', // blue\n '#F0E442', // yellow\n '#AAAAAA', // grey\n ],\n axis : 'rgb(176, 176, 176)',\n grid : 'rgb(58, 58, 58)',\n label : 'rgb(192, 192, 192)',\n selection: '#4a9eff',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Panel, PanelOptions } from \"~/core/Panel.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Form}.\n *\n * @category Core\n */\nexport interface FormOptions extends PanelOptions {\n /**\n * Called after a native form submission is requested — via the submit\n * button, Enter in a field, or `requestSubmit()`. The framework has already\n * called `preventDefault()` on the submit event, so the page will not\n * navigate; the handler owns what submission means.\n */\n onSubmit?: (form: Form) => void;\n}\n\n/**\n * A {@link Panel} that bakes the semantic `<form>` tag and wires the native\n * `submit` event to a single `onSubmit` callback.\n *\n * Use `Form` as the content surface for a group of fields that should submit\n * together — it inherits `Panel`'s 4-pixel insets and `autoScroll` stack, so a\n * tall form in a short area scrolls rather than inflating to content size.\n * Trigger a submission from an external control (e.g. a footer button outside\n * the form) via {@link Form.requestSubmit}, which reaches the browser's native\n * `HTMLFormElement.requestSubmit()` — firing the cancelable `submit` event and\n * running constraint validation — through the `DOM.sink` seam, mirroring how\n * {@link Component.focus} reaches the native `focus()`.\n *\n * @example\n * ```typescript\n * const form = new Form({\n * onSubmit: (f) => console.log('submitted'),\n * });\n * // ...\n * submitButton.on(\"action\", () => form.requestSubmit());\n * ```\n *\n * @category Core\n */\nclass Form<TOptions extends FormOptions = FormOptions> extends Panel<TOptions> {\n\n private _onSubmit: ((form: Form) => void) | null = null;\n\n /**\n * @param options - Optional. Construction-time options applied to the form.\n */\n constructor(options?: TOptions) {\n super(options, { tag: \"form\" } as Partial<TOptions>);\n\n // Wire after super() returns: Event.addListener needs the fully\n // constructed component, and this is the deferred-dispatch site the\n // super-cascade trap requires (never applyOptions).\n this._onSubmit = options?.onSubmit ?? null;\n Event.addListener(this, \"submit\", this.handleSubmit);\n }\n\n /**\n * Handles the native `submit` event: prevents the browser's default\n * navigation and forwards to the `onSubmit` callback, if any.\n *\n * @param e - The native submit event.\n */\n private handleSubmit(e: SubmitEvent): void {\n e.preventDefault();\n this._onSubmit?.(this);\n }\n\n /**\n * Requests a native form submission, firing the cancelable `submit` event\n * and running the browser's constraint validation (unlike `.submit()`,\n * which skips both). No-op if the form is not yet rendered.\n */\n requestSubmit(): void {\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n DOM.sink.requestSubmit(element);\n }\n}\n\nconst FormCallable = callable(Form);\ntype FormCallable<TOptions extends FormOptions = FormOptions> = Form<TOptions>;\nexport {\n Form as _Form,\n FormCallable as Form,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ThemeManager, ModernTheme } from \"~/core/Theme.js\";\n\n/**\n * A {@link Component} that wraps the page's `<body>` element.\n *\n * Use the singleton accessor to add top-level components to the page:\n * ```\n * let body = Body.getInstance();\n * body.addComponent(....);\n * ```\n *\n * @category Core\n */\nexport class Body extends Component {\n\n private static readonly INSTANCE: Body = new Body();\n\n /**\n * Returns the singleton Body instance.\n *\n * @returns The single shared Body component for this page.\n */\n static getInstance() {\n return this.INSTANCE;\n }\n\n /**\n * Applies an options bag to the singleton Body and returns it — the\n * ergonomic entry point for mounting a top-level layout in one call:\n * `Body.init({ layoutManager: Fit(), components: [shell] })`. Only the\n * supplied fields are dispatched (it delegates to\n * `Component.applyOptions`), so the body's viewport-size tracking and\n * theme set up at construction are preserved.\n *\n * @param options - Component options to apply (layout manager, children, …).\n *\n * @returns The singleton Body instance, for chaining.\n */\n static init(options: ComponentOptions = {}): Body {\n this.INSTANCE.applyOptions(options);\n\n return this.INSTANCE;\n }\n\n private constructor() {\n super({ tag: \"body\" });\n\n this.init();\n\n this.setBackgroundColor(\"var(--ts-ui-body-bg, rgb(241, 241, 241))\");\n\n ThemeManager.setTheme(ModernTheme);\n }\n\n /**\n * Returns the document body element.\n *\n * @returns The `<body>` HTMLElement.\n */\n getElement() {\n return DOM.source.getBody();\n }\n\n /**\n * Initializes the body size from the viewport and registers a resize listener to keep it in sync.\n *\n * @returns This component, for method chaining.\n */\n protected init(): this {\n super.init();\n\n this.setSize(DOM.source.getViewportSize());\n this.clearInsets();\n\n Event.addViewportListener(this, \"resize\", this._onViewportResize);\n\n return this;\n }\n\n /**\n * Bound viewport-resize handler. Reads the current viewport extent on\n * each fire (DOM `resize` events carry no payload) and writes it\n * through the typed setter.\n */\n private _onViewportResize = (): void => {\n this.setSize(DOM.source.getViewportSize());\n };\n\n /**\n * Overrides {@link Component.clampsToContentSize} to `false`: the body *is*\n * the viewport, so its size must track {@link Util.getViewportSize} exactly\n * and let oversized content overflow (the page scrolls / a child `Panel`\n * scrolls internally) rather than inflating the body up to its\n * content-derived minimum. With the `Component` default (`true`),\n * {@link Component.setSize} ran the viewport extent through\n * {@link Component.clampHeight}, which floored it to `getMinSize()` — the\n * tall content's minimum — so once that minimum was measured the body could\n * never shrink back below its content when the viewport shrank.\n *\n * @returns `false`, so size clamping uses the body's own explicit\n * constraints only, not its content-derived ones.\n */\n protected clampsToContentSize(): boolean {\n return false;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\n\n/**\n * A physical-key chord. `code` is a `KeyboardEvent.code` value (layout-independent).\n *\n * @category Core\n */\nexport interface FocusHistoryKeyCombo {\n code: string;\n ctrl?: boolean;\n alt?: boolean;\n shift?: boolean;\n meta?: boolean;\n}\n\n/**\n * Options for {@link FocusHistory.enable} / {@link FocusHistory.configure}.\n *\n * @category Core\n */\nexport interface FocusHistoryOptions {\n /** Max entries retained; oldest dropped past this. Default 50. */\n maxSize?: number;\n /** Back accelerator. Default `Alt+[` (`{ code: \"BracketLeft\", alt: true }`). */\n back?: FocusHistoryKeyCombo;\n /** Forward accelerator. Default `Alt+]` (`{ code: \"BracketRight\", alt: true }`). */\n forward?: FocusHistoryKeyCombo;\n}\n\n/**\n * The sole custom event name fired by {@link FocusHistory}.\n *\n * @category Core\n */\nexport type FocusHistoryEvent = \"change\";\n\n/**\n * Payload of the `\"change\"` event: the navigability of the trail after the change.\n *\n * @category Core\n */\nexport interface FocusHistoryChange {\n canGoBack: boolean;\n canGoForward: boolean;\n}\n\n// 50: a working session's focus trail rarely exceeds a few dozen stops; caps\n// memory at 50 handle numbers while leaving generous back-depth.\nconst DEFAULT_MAX_ENTRIES: number = 50;\n// Alt+[ / Alt+]: editor-style \"navigate back/forward\"; no default browser\n// action (unlike Alt+Left/Right = browser history); layout-independent via code.\nconst DEFAULT_BACK_COMBO: FocusHistoryKeyCombo = { code: \"BracketLeft\", alt: true };\nconst DEFAULT_FORWARD_COMBO: FocusHistoryKeyCombo = { code: \"BracketRight\", alt: true };\n\n// Sentinel used to register the service's viewport listeners — see\n// LayerManager's identical `_listenerOwner` pattern. `FocusHistory` has no DOM\n// element of its own, so a stable, otherwise-unused `Component` owns them.\nconst _owner: Component = new Component();\nconst _listeners = new ListenerBag<FocusHistoryEvent>();\n\n// Chronological trail, oldest first. Entries are bare `Handle`s (not\n// `Component`s) because focus frequently lands on an element with no 1:1\n// component (an input inside a Text, a raw button).\nlet _entries: Handle[] = [];\n// Current position in `_entries`; -1 when the trail is empty.\nlet _index: number = -1;\nlet _enabled: boolean = false;\n// Re-entrancy guard: true for the duration of a service-driven `DOM.sink.focus`\n// call, so the synchronous `focusin` it triggers is not recorded as a new move.\nlet _navigating: boolean = false;\nlet _maxSize: number = DEFAULT_MAX_ENTRIES;\nlet _back: FocusHistoryKeyCombo = DEFAULT_BACK_COMBO;\nlet _forward: FocusHistoryKeyCombo = DEFAULT_FORWARD_COMBO;\n\n/**\n * Whether `handle` still resolves to a connected element. A GC-collected weak\n * handle throws on resolve inside the DOM seam; that is treated as stale too.\n */\nfunction isLive(handle: Handle): boolean {\n try {\n return DOM.source.isConnected(handle);\n } catch {\n return false;\n }\n}\n\n/**\n * Drops every stale (no-longer-connected) entry from the trail, keeping\n * `_index` pointed at the nearest surviving entry at or before its old\n * position (or -1 if nothing survived there). Run before every navigation\n * and every `canGo*` query so those never act on a dead entry.\n */\nfunction pruneStale(): void {\n const kept: Handle[] = [];\n let newIndex = -1;\n\n for (let i = 0; i < _entries.length; i++) {\n const handle = _entries[i];\n\n if (isLive(handle)) {\n kept.push(handle);\n\n if (i <= _index) {\n newIndex = kept.length - 1;\n }\n }\n }\n\n _entries = kept;\n _index = newIndex;\n}\n\n/** Computes the current navigability and notifies `\"change\"` listeners. */\nfunction fireChange(): void {\n const change: FocusHistoryChange = {\n canGoBack: _index > 0,\n canGoForward: _index < _entries.length - 1,\n };\n\n _listeners.fire(\"change\", change);\n}\n\n/**\n * Appends `handle` to the trail (deduping a repeat of the current entry and\n * truncating any forward branch), advances `_index`, and fires `\"change\"`.\n */\nfunction record(handle: Handle): void {\n if (_index >= 0 && _entries[_index] === handle) {\n return;\n }\n\n _entries.length = _index + 1;\n _entries.push(handle);\n\n while (_entries.length > _maxSize) {\n _entries.shift();\n }\n\n _index = _entries.length - 1;\n fireChange();\n}\n\n/** Re-focuses `handle` under the re-entrancy guard, then fires `\"change\"`. */\nfunction focusEntry(handle: Handle): void {\n _navigating = true;\n DOM.sink.focus(handle);\n _navigating = false;\n fireChange();\n}\n\n/**\n * Prunes stale entries, then moves `_index` by `direction` and re-focuses the\n * entry there, if one exists.\n *\n * @returns True if focus moved.\n */\nfunction navigate(direction: -1 | 1): boolean {\n pruneStale();\n\n const target = _index + direction;\n\n if (target < 0 || target >= _entries.length) {\n return false;\n }\n\n _index = target;\n focusEntry(_entries[_index]);\n\n return true;\n}\n\n/** Whether a `KeyboardEvent` matches a configured combo. */\nfunction matchesCombo(e: KeyboardEvent, combo: FocusHistoryKeyCombo): boolean {\n return e.code === combo.code &&\n e.altKey === !!combo.alt && e.ctrlKey === !!combo.ctrl &&\n e.shiftKey === !!combo.shift && e.metaKey === !!combo.meta;\n}\n\n/** Document `focusin` handler: records the newly-focused element. */\nfunction onFocusIn(e: FocusEvent): void {\n if (!_enabled || _navigating) {\n return;\n }\n\n if (!DOM.source.isElement(e.target)) {\n return;\n }\n\n record(DOM.source.intern(e.target));\n}\n\n/**\n * Document `keydown` handler: drives `back()`/`forward()` on the configured\n * combos, suppressed while a modal layer is on top so the accelerator does\n * not fight the modal's own focus trap.\n */\nfunction onKeyDown(e: KeyboardEvent): void {\n if (!_enabled) {\n return;\n }\n\n const direction: -1 | 1 | 0 = matchesCombo(e, _back) ? -1 : matchesCombo(e, _forward) ? 1 : 0;\n\n if (direction === 0) {\n return;\n }\n\n const top = LayerManager.getTopLayer();\n\n if (top && top.getDismissMode() === \"modal\") {\n return;\n }\n\n e.preventDefault();\n navigate(direction);\n}\n\n/**\n * Global focus-trail navigation service: records the chronological order in\n * which elements receive keyboard focus across the document and drives an\n * accelerator that walks the trail backward and forward, like browser\n * back/forward but for keyboard focus. Opt-in — call {@link enable} to start\n * recording; nothing auto-starts it.\n *\n * @category Core\n */\nexport namespace FocusHistory {\n /**\n * Installs the `focusin` + `keydown` listeners, seeds the trail with the\n * current active element (if any), and begins recording. Idempotent —\n * calling it again while already enabled only applies `options`.\n *\n * @param options - Optional `maxSize` / combo overrides, applied via\n * {@link configure} before enabling.\n */\n export function enable(options?: FocusHistoryOptions): void {\n if (options) {\n configure(options);\n }\n\n if (_enabled) {\n return;\n }\n\n _enabled = true;\n\n Event.addViewportListener(_owner, \"focusin\", onFocusIn);\n Event.addViewportListener(_owner, \"keydown\", onKeyDown);\n\n const active = DOM.source.getActiveElement();\n\n if (active !== null) {\n record(active);\n }\n }\n\n /**\n * Removes the listeners and stops recording. Preserves the trail —\n * re-enabling resumes from where it left off. Idempotent.\n */\n export function disable(): void {\n if (!_enabled) {\n return;\n }\n\n _enabled = false;\n _navigating = false;\n\n Event.removeViewportListener(_owner, \"focusin\", onFocusIn);\n Event.removeViewportListener(_owner, \"keydown\", onKeyDown);\n }\n\n /** Whether the service is currently observing. */\n export function isEnabled(): boolean {\n return _enabled;\n }\n\n /**\n * Updates `maxSize` / combos without toggling enablement. Only the\n * supplied fields change.\n *\n * @param options - The fields to update.\n */\n export function configure(options: FocusHistoryOptions): void {\n if (options.maxSize !== undefined) {\n _maxSize = options.maxSize;\n }\n\n if (options.back !== undefined) {\n _back = options.back;\n }\n\n if (options.forward !== undefined) {\n _forward = options.forward;\n }\n }\n\n /**\n * Re-focuses the previous live entry, skipping and dropping any stale\n * ones encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function back(): boolean {\n return navigate(-1);\n }\n\n /**\n * Re-focuses the next live entry, skipping and dropping any stale ones\n * encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function forward(): boolean {\n return navigate(1);\n }\n\n /**\n * Whether a live entry exists before the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoBack(): boolean {\n pruneStale();\n\n return _index > 0;\n }\n\n /**\n * Whether a live entry exists after the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoForward(): boolean {\n pruneStale();\n\n return _index < _entries.length - 1;\n }\n\n /** Empties the trail and fires `\"change\"` with both flags false. */\n export function clear(): void {\n _entries = [];\n _index = -1;\n fireChange();\n }\n\n /**\n * Subscribes to trail-navigability changes, fired after every recorded\n * focus move and after every `back()` / `forward()` navigation.\n *\n * @param event - Always `\"change\"`.\n * @param listener - Invoked with the trail's navigability after the change.\n */\n export function on(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.add(event, listener);\n }\n\n /**\n * Unsubscribes a `\"change\"` listener.\n *\n * @param event - Always `\"change\"`.\n * @param listener - The exact callback reference passed to {@link on}.\n */\n export function off(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.remove(event, listener);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from '~/core/BaseObject.js';\nimport { ModelRecord } from '~/data/ModelRecord.js';\nimport { Bindable, BindingAccessors } from '~/core/Bindable.js';\nimport { Component } from '~/core/Component.js';\nimport { ListenerBag } from '~/core/ListenerBag.js';\nimport { ValidationRule, FieldValidationConfig } from '~/validation/ValidationRule.js';\nimport { FieldDecorator } from '~/validation/FieldDecorator.js';\nimport { applyRule } from '~/validation/Validator.js';\n\n/**\n * String-literal union of events emitted by {@link Binding}.\n *\n * @category Data\n */\nexport type BindingEvent = \"change\" | \"commit\" | \"reject\" | \"beforerecord\";\n\ninterface BoundEntry {\n accessors: BindingAccessors<any>;\n active: boolean;\n}\n\n/**\n * Listener consulted before a record change takes effect.\n *\n * Receives the *next* record (or `null`) and returns `false` to cancel the\n * change. Any other return value (`true`, `undefined`, …) allows it.\n *\n * @category Data\n */\nexport type BeforeRecordListener = (next: ModelRecord | null) => boolean;\n\n/**\n * Synchronises a {@link ModelRecord} with a set of UI components.\n *\n * Components are registered with {@link bind}, either as {@link Bindable} implementors\n * (short form) or via explicit accessor callbacks (long form). Once a record is loaded\n * via {@link setRecord}, every bound component is populated from the record's fields.\n * Conversely, whenever a component's value changes, the record is updated automatically.\n *\n * @example Short form — component implements Bindable\n * ```typescript\n * const binding = new Binding()\n * .bind('name', nameField)\n * .bind('active', activeCheckbox)\n * .bind('role', roleCombo);\n *\n * binding.setRecord(record);\n * ```\n *\n * @example Long form — explicit accessors for any component\n * ```typescript\n * const binding = new Binding()\n * .bind('name', myWidget, {\n * get: () => myWidget.getValue(),\n * set: (v) => myWidget.setValue(v),\n * listen: (fn) => myWidget.on(\"change\", fn),\n * });\n * ```\n *\n * @category Data\n */\nexport class Binding extends BaseObject {\n\n private _record: ModelRecord | null = null;\n private _entries: Map<string, BoundEntry> = new Map();\n private _listeners: ListenerBag<BindingEvent> = new ListenerBag<BindingEvent>();\n private _validationConfigs: Map<string, FieldValidationConfig> = new Map();\n private _globalValidateOnChange: boolean = false;\n private _loading: boolean = false;\n\n // ── Registration ────────────────────────────────────────────────────────\n\n /**\n * Registers a field binding using a component that implements {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - A component implementing the {@link Bindable} interface.\n */\n bind<T>(fieldName: string, component: Bindable<T>): this;\n\n /**\n * Registers a field binding using explicit accessor callbacks.\n * Use this overload for components that do not implement {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - Any object (used only as a placeholder for the overload).\n * @param accessors - Getter, setter, and change-listener callbacks.\n */\n bind<T>(fieldName: string, component: object, accessors: BindingAccessors<T>): this;\n\n bind<T>(fieldName: string, component: Bindable<T> | object, accessors?: BindingAccessors<T>): this {\n this.unbind(fieldName);\n\n const acc: BindingAccessors<any> = accessors ?? {\n get: () => (component as Bindable<T>).getValue(),\n set: (v: T) => (component as Bindable<T>).setValue(v),\n listen: (fn) => (component as Bindable<T>).on(\"binding\", fn),\n };\n\n const entry: BoundEntry = { accessors: acc, active: true };\n this._entries.set(fieldName, entry);\n\n acc.listen(() => {\n if (this._loading) {\n return;\n }\n\n if (!entry.active || !this._record) {\n return;\n }\n\n const value = acc.get();\n this._record.set(fieldName, value);\n\n this.emit(\"change\", fieldName, value);\n\n this._validateFieldIfLive(fieldName);\n });\n\n if (this._record) {\n acc.set(this._record.get(fieldName));\n }\n\n return this;\n }\n\n /**\n * Removes the binding for the given field.\n * The change listener previously attached to the component becomes a no-op.\n *\n * @param fieldName - The field whose binding should be removed.\n */\n unbind(fieldName: string): this {\n const entry = this._entries.get(fieldName);\n if (entry) {\n entry.active = false;\n\n this._entries.delete(fieldName);\n }\n\n return this;\n }\n\n // ── Record management ────────────────────────────────────────────────────\n\n /**\n * Loads a record into the binding. All registered components are immediately\n * populated with the corresponding field values. Pass `null` to clear the binding.\n *\n * Before any state mutation, every `on(\"beforerecord\", fn)` listener is\n * consulted; if any returns `false` the\n * call is a complete no-op (no validation reset, no field population) and\n * `this` is returned unchanged.\n *\n * @param record - The record to bind, or `null` to detach.\n */\n setRecord(record: ModelRecord | null): this {\n for (const fn of this._listeners.get(\"beforerecord\") as BeforeRecordListener[]) {\n if (fn(record) === false) {\n return this;\n }\n }\n\n this._record = record;\n\n this.clearValidation();\n\n if (!record) {\n return this;\n }\n\n this._loading = true;\n\n try {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(record.get(fieldName));\n }\n } finally {\n this._loading = false;\n }\n\n for (const [fieldName] of this._validationConfigs) {\n this._validateFieldIfLive(fieldName);\n }\n\n return this;\n }\n\n /**\n * Returns the currently bound record, or `null` if none is loaded.\n */\n getRecord(): ModelRecord | null {\n return this._record;\n }\n\n // ── Commit / reject ──────────────────────────────────────────────────────\n\n /**\n * Commits the current record, clearing its dirty and new flags.\n * Fires all registered commit listeners.\n */\n commit(): this {\n this._record?.commit();\n\n this.emit(\"commit\");\n\n return this;\n }\n\n /**\n * Rejects all changes on the current record and re-syncs every component\n * from the reverted field values. Fires all registered reject listeners.\n * Also clears any active validation error decorations.\n */\n reject(): void {\n this._record?.reject();\n\n if (this._record) {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(this._record.get(fieldName));\n }\n }\n\n this.clearValidation();\n\n this.emit(\"reject\");\n }\n\n // ── Listeners ────────────────────────────────────────────────────────────\n\n /**\n * Registers a listener for one of this binding's events.\n *\n * @param event - `\"change\"` fires whenever any bound component changes a\n * field value, receiving `(fieldName, value)`. `\"commit\"` fires after\n * {@link commit}. `\"reject\"` fires after {@link reject}.\n * `\"beforerecord\"` is consulted before {@link setRecord} mutates state;\n * returning `false` vetoes the call as a complete no-op.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This binding, for method chaining.\n *\n * @remarks `\"beforerecord\"` veto semantics: iteration stops on the first\n * `false`; if any listener vetoes, {@link setRecord} returns without\n * modifying any state. Returning `true` — or anything other than\n * `false`, including `undefined` — allows the change. Async\n * confirmation must be handled at the call site — {@link setRecord}\n * stays synchronous. A listener that itself calls {@link setRecord}\n * re-enters the same veto loop, which is supported but discouraged.\n * `null` is a valid `next` value (it represents a clear); a listener\n * that only wants to guard non-clear switches must short-circuit\n * `next === null` itself.\n */\n on(event: \"change\", listener: (fieldName: string, value: unknown) => void): this;\n on(event: \"commit\", listener: () => void): this;\n on(event: \"reject\", listener: () => void): this;\n on(event: \"beforerecord\", listener: BeforeRecordListener): this;\n on(event: BindingEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This binding, for method chaining.\n */\n off(event: BindingEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order. Internal use only — external callers route\n * dispatch through {@link commit} / {@link reject} / {@link setRecord}.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"change\", fieldName: string, value: unknown): void;\n protected emit(event: \"commit\"): void;\n protected emit(event: \"reject\"): void;\n protected emit(event: BindingEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n // ── Validation ───────────────────────────────────────────────────────────\n\n /**\n * Attaches one or more validation rules to a bound field.\n *\n * @param fieldName - The field name registered with {@link bind}.\n * @param component - The Component instance to wrap with a {@link FieldDecorator} on error.\n * @param rules - One or more {@link ValidationRule} objects to apply to this field.\n *\n * @returns this, for chaining.\n */\n addValidation(fieldName: string, component: Component, rules: ValidationRule | ValidationRule[]): this {\n const ruleArray = Array.isArray(rules) ? rules : [rules];\n\n this._validationConfigs.set(fieldName, {\n rules : ruleArray,\n component,\n validateOnChange: false,\n decorator : null,\n });\n\n return this;\n }\n\n /**\n * Removes all validation rules for a field and clears any existing error decoration.\n *\n * @param fieldName - The field whose validation should be removed.\n *\n * @returns this, for chaining.\n */\n removeValidation(fieldName: string): this {\n const config = this._validationConfigs.get(fieldName);\n\n if (config?.decorator) {\n config.decorator.clearError();\n }\n\n this._validationConfigs.delete(fieldName);\n\n return this;\n }\n\n /**\n * Runs all registered validation rules against the current field values.\n * Applies or clears {@link FieldDecorator} error state for each validated field.\n *\n * @returns true if all fields pass; false if any field fails.\n */\n validate(): boolean {\n let allValid = true;\n\n for (const [fieldName] of this._validationConfigs) {\n const valid = this._validateField(fieldName);\n\n if (!valid) {\n allValid = false;\n }\n }\n\n return allValid;\n }\n\n /**\n * Enables or disables live validation (validation on every field change).\n *\n * @param enabled - true to validate on every change event; false for explicit-only.\n */\n setValidateOnChange(enabled: boolean): this {\n this._globalValidateOnChange = enabled;\n\n return this;\n }\n\n /**\n * Returns whether live validation is globally enabled.\n *\n * @returns true if live validation is active.\n */\n getValidateOnChange(): boolean {\n return this._globalValidateOnChange;\n }\n\n /**\n * Clears all error decorations without re-running rules.\n * Called automatically by {@link reject}.\n */\n clearValidation(): this {\n for (const [, config] of this._validationConfigs) {\n if (config.decorator) {\n config.decorator.clearError();\n }\n }\n\n return this;\n }\n\n /**\n * Validates a single field and updates its decorator.\n *\n * @param fieldName - The field to validate.\n *\n * @returns true if the field passes all rules.\n */\n private _validateField(fieldName: string): boolean {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return true;\n }\n\n const entry = this._entries.get(fieldName);\n const value = entry ? entry.accessors.get() : undefined;\n\n for (const rule of config.rules) {\n const result = applyRule(rule, value);\n\n if (result.valid) {\n continue;\n }\n\n if (!config.decorator) {\n const parent = config.component.getParentComponent();\n\n if (parent) {\n config.decorator = new FieldDecorator(config.component, parent);\n }\n }\n\n config.decorator?.showError(result.message);\n\n return false;\n }\n\n config.decorator?.clearError();\n\n return true;\n }\n\n /**\n * Calls {@link _validateField} only if live validation is active for this field.\n *\n * @param fieldName - The field to conditionally validate.\n */\n private _validateFieldIfLive(fieldName: string): void {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return;\n }\n\n const live = config.validateOnChange || this._globalValidateOnChange;\n\n if (live) {\n this._validateField(fieldName);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.es.js","names":[],"sources":["../../src/typescript/lib/core/themes/ClassicTheme.ts","../../src/typescript/lib/core/themes/DarkTheme.ts","../../src/typescript/lib/core/Form.ts","../../src/typescript/lib/core/Body.ts","../../src/typescript/lib/core/FocusHistory.ts","../../src/typescript/lib/core/Binding.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Classic light theme using white backgrounds, black text, and gradient\n * buttons. The original default look, retained as an opt-in alternative now\n * that {@link ModernTheme} is the preselected theme.\n *\n * Authored as `defineTheme(BaseTheme, …)`: it declares only its palette (and\n * `colorScheme`); every structural token is inherited from {@link BaseTheme}.\n * Classic carries no structural override — its `tab.underBorderFullWidth`\n * already matches the base value.\n *\n * @category Theme\n */\nexport const ClassicTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'light',\n text : { color: 'rgb(0, 0, 0)' },\n body : { background: 'rgb(255, 255, 255)' },\n border : { color: 'black' },\n button : {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : 'rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n description: {\n foreground: 'rgb(110, 110, 110)',\n },\n pressed : {\n foreground: 'rgb(150, 150, 150)',\n background: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.30)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.25)',\n },\n flat : {\n hover : {\n background: 'rgba(0, 0, 0, 0.06)',\n border : '1px solid rgb(200, 200, 200)',\n },\n pressed: {\n background: 'rgba(0, 0, 0, 0.10)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.25)',\n border : '1px solid rgb(180, 180, 180)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(200, 200, 200)',\n shadow : '2px 2px 1px inset grey',\n },\n },\n input : {\n background : 'rgb(255, 255, 255)',\n border : '1px solid rgb(160, 160, 160)',\n borderHover: '1px solid rgb(120, 120, 120)',\n },\n form : {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(160, 160, 160)',\n color : 'rgb(40, 40, 40)',\n disabledBackground: 'rgb(240, 240, 240)',\n disabledColor : 'rgb(170, 170, 170)',\n focusRing : 'rgb(30, 100, 200)',\n toggle : {\n trackOffBackground: 'rgb(200, 200, 200)',\n trackOnBackground : 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n slider : {\n trackBackground : 'rgb(220, 220, 220)',\n trackActiveBackground: 'rgb(30, 100, 200)',\n thumbBackground : 'rgb(255, 255, 255)',\n },\n checkbox: {\n background : 'rgb(255, 255, 255)',\n selectedBackground : 'rgb(30, 100, 200)',\n indeterminateBackground: 'rgb(160, 160, 160)',\n checkColor : 'rgb(255, 255, 255)',\n },\n radio : {\n background : 'rgb(255, 255, 255)',\n selectedBackground: 'rgb(30, 100, 200)',\n dotColor : 'rgb(255, 255, 255)',\n },\n },\n gutter: { background: '#AAAAAA' },\n collapse: {\n strip: { background: '#AAAAAA', size: '18px' },\n button: { color: 'rgb(100,100,100)' },\n },\n accordion: {\n border : '1px solid rgb(190,190,190)',\n header : {\n background: 'linear-gradient(rgb(230,230,230),rgb(210,210,210))',\n border : '1px solid rgb(190,190,190)',\n color : 'inherit',\n },\n panel : { border: 'rgb(210,210,210)' },\n indicator: { color: 'rgb(100,100,100)' },\n },\n tab : {\n toolbar: { background: '#eee', border: '#e1e1e8' },\n button : {\n background: 'linear-gradient(rgb(208, 208, 216), rgb(185, 185, 196))',\n border : 'none',\n hover : { background: 'linear-gradient(rgb(220, 220, 227), rgb(198, 198, 208))', border: 'none' },\n selected : { background: 'linear-gradient(rgb(255, 255, 255), rgb(235, 235, 240))', border: 'none' },\n },\n indicator: { color: '#1a73e8' },\n },\n window: {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.4)',\n snapGlow : '0 0 0 2px rgba(30, 100, 200, 0.7)',\n control : {\n background : 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border : '1px solid rgb(200, 200, 200)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.2)',\n hoverBackground : 'linear-gradient(rgb(252, 252, 252), rgb(220, 220, 220))',\n activeBackground: 'linear-gradient(rgb(200, 200, 200), rgb(214, 214, 214))',\n },\n header : { background: '#eee' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200))',\n border: 'black',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.15)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.6)',\n new : 'rgba(70, 200, 70, 0.15)',\n dirty : 'rgba(255, 165, 0, 0.15)',\n stripe : 'rgba(0, 0, 0, 0.035)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(0, 0, 0, 0.04)',\n requiredEmptyOutlineColor : 'rgba(220, 60, 60, 0.6)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.6)',\n },\n resizeHandle: {\n color : 'rgba(0, 0, 0, 0.2)',\n },\n sortBadge: {\n background: 'rgba(0, 0, 0, 0.15)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(30, 100, 200, 0.10)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n },\n item : {\n hoverBackground: 'rgba(30, 100, 200, 0.12)',\n disabledColor : 'rgb(170, 170, 170)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(220, 220, 220)',\n },\n statusBar: {\n background: 'rgb(245, 245, 245)',\n color : 'rgb(60, 60, 60)',\n border : 'rgb(220, 220, 220)',\n },\n toolBar: {\n background : 'rgb(245, 245, 245)',\n border : 'rgb(220, 220, 220)',\n separatorColor: 'rgb(220, 220, 220)',\n },\n tooltip: {\n background: 'rgb(255, 255, 240)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(180, 180, 100)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.2)',\n },\n popover: {\n background: 'rgb(255, 255, 255)',\n color : 'rgb(0, 0, 0)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.18)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.15)',\n info : { background: 'rgba(210, 224, 244, 0.75)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(210, 240, 220, 0.75)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(248, 232, 204, 0.75)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(244, 214, 214, 0.75)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(200, 50, 50)',\n tooltip: {\n background: 'rgb(180, 30, 30)',\n color : 'rgb(255, 255, 255)',\n border : 'rgb(140, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 4px 8px rgba(0,0,0,0.15)',\n item: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n highlightBackground: 'rgba(30, 100, 200, 0.18)',\n highlightColor : 'inherit',\n disabledColor : 'rgb(170, 170, 170)',\n },\n },\n // Defaults mirror `autoComplete` numerically because both surfaces present\n // selectable rows; a theme that customises one gets the other matching\n // automatically. `row.separator` defaults to `transparent` so the visual\n // matches the prior native `<select>` (no row hairlines); themes can opt\n // in to a denser look by overriding to a `1px solid rgba(...)` colour.\n list: {\n background: 'rgb(255, 255, 255)',\n border : 'rgb(200, 200, 200)',\n row: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.18)',\n selectedColor : 'inherit',\n focusRing : 'rgb(30, 100, 200)',\n disabledColor : 'rgb(170, 170, 170)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(30, 100, 200)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Picker tokens stay numerically in step with `autoComplete.item.*` — they\n // share the {@link PickerCell} class — so a theme that customises one\n // gets the other matching automatically.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(30, 100, 200, 0.08)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.45)' },\n border : 'rgb(220, 220, 220)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.35)',\n confirm : 'rgb(30, 180, 80)',\n cancel : 'rgb(200, 50, 50)',\n info : { background: 'rgba(30, 100, 200, 0.15)', foreground: 'rgb(30, 100, 200)' },\n affirm : { background: 'rgba(30, 180, 80, 0.15)', foreground: 'rgb(30, 180, 80)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.25)',\n border : 'rgb(220, 220, 220)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(200, 200, 200)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.18)',\n handle: {\n hoverBackground : 'rgba(30, 100, 200, 0.08)',\n selectedBackground: 'rgba(30, 100, 200, 0.16)',\n },\n },\n spinner: {\n dividerColor: 'rgb(180, 180, 180)',\n },\n progressBar: {\n track : { background: 'rgb(220, 220, 220)' },\n fill : { background: 'rgb(30, 100, 200)' },\n indeterminate: { background: 'rgb(30, 100, 200)' },\n },\n progressSpinner: {\n color : 'rgb(30, 100, 200)',\n backdrop: 'rgba(255, 255, 255, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(200, 200, 200, 0.9)',\n border : 'rgb(150, 150, 150)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.25)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.12)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.10)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(30, 100, 200)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : 'rgba(80, 140, 240, 0.40)',\n activeBackground : 'rgba(80, 140, 240, 0.28)',\n invalidBackground: 'rgba(200, 50, 50, 0.28)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.06)',\n border : '2px dashed rgba(80, 140, 240, 0.40)',\n activeBackground: 'rgba(80, 140, 240, 0.18)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.80)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito colour-blind-safe categorical palette, tuned for a light\n // background (Classic is a light scheme). Neutral grey axis/grid/label; the\n // selection ring reuses the theme's blue accent.\n chart: {\n series: [\n '#0072B2', // blue\n '#E69F00', // orange\n '#009E73', // green\n '#D55E00', // vermilion\n '#CC79A7', // purple\n '#56B4E9', // sky\n '#8C6D1F', // gold\n '#555555', // grey\n ],\n axis : 'rgb(120, 120, 120)',\n grid : 'rgb(220, 220, 220)',\n label : 'rgb(80, 80, 80)',\n selection: '#1a73e8',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseTheme } from '~/core/themes/BaseTheme.js';\nimport { defineTheme } from '~/core/Theme.js';\nimport type { Theme } from '~/core/Theme.js';\n\n/**\n * Dark-mode theme using dark backgrounds and light text.\n *\n * Authored as `defineTheme(BaseTheme, …)`: beyond its palette and\n * `colorScheme: 'dark'`, its only structural divergence is\n * `tab.underBorderFullWidth: false` (the base value is `true`). Every other\n * structural token is inherited from {@link BaseTheme}.\n *\n * @category Theme\n */\nexport const DarkTheme: Theme = defineTheme(BaseTheme, {\n colorScheme: 'dark',\n text : { color: 'rgb(220, 220, 220)' },\n body : { background: 'rgb(30, 30, 30)' },\n border : { color: 'rgb(90, 90, 90)' },\n button : {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border : 'rgb(80, 80, 80)',\n shadow : '1px 2px 5px 0 rgba(0, 0, 0, 0.5)',\n description: {\n foreground: 'rgb(160, 160, 160)',\n },\n pressed : {\n foreground: 'rgb(180, 180, 180)',\n background: 'linear-gradient(rgb(35, 35, 35), rgb(48, 48, 48))',\n shadow : 'inset 0 1px 4px rgba(0, 0, 0, 0.6)',\n },\n hover : {\n foreground: 'inherit',\n background: 'linear-gradient(rgb(90, 90, 90), rgb(65, 65, 65))',\n shadow : '1px 3px 6px 0 rgba(0, 0, 0, 0.55)',\n },\n flat : {\n hover : {\n background: 'rgba(255, 255, 255, 0.08)',\n border : '1px solid rgb(90, 90, 90)',\n },\n pressed: {\n background: 'rgba(255, 255, 255, 0.12)',\n shadow : 'inset 1px 1px 3px rgba(0, 0, 0, 0.55)',\n border : '1px solid rgb(70, 70, 70)',\n },\n },\n },\n toggle : {\n selected: {\n background: 'rgb(35, 35, 35)',\n shadow : '2px 2px 1px inset #333',\n },\n },\n input : {\n background : 'rgb(40, 40, 40)',\n border : '1px solid rgb(110, 110, 110)',\n borderHover: '1px solid rgb(150, 150, 150)',\n },\n form : {\n background : 'rgb(40, 40, 40)',\n border : 'rgb(110, 110, 110)',\n color : 'rgb(230, 230, 230)',\n disabledBackground: 'rgb(60, 60, 60)',\n disabledColor : 'rgb(120, 120, 120)',\n focusRing : 'rgb(120, 170, 240)',\n toggle : {\n trackOffBackground: 'rgb(70, 70, 70)',\n trackOnBackground : 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n slider : {\n trackBackground : 'rgb(70, 70, 70)',\n trackActiveBackground: 'rgb(120, 170, 240)',\n thumbBackground : 'rgb(230, 230, 230)',\n },\n checkbox: {\n background : 'rgb(40, 40, 40)',\n selectedBackground : 'rgb(120, 170, 240)',\n indeterminateBackground: 'rgb(100, 100, 100)',\n checkColor : 'rgb(20, 20, 20)',\n },\n radio : {\n background : 'rgb(40, 40, 40)',\n selectedBackground: 'rgb(120, 170, 240)',\n dotColor : 'rgb(20, 20, 20)',\n },\n },\n gutter: { background: '#555' },\n collapse: {\n strip: { background: '#555', size: '18px' },\n button: { color: 'rgb(160,160,160)' },\n },\n accordion: {\n border : '1px solid rgb(80,80,80)',\n header : {\n background: 'linear-gradient(rgb(60,60,60),rgb(45,45,45))',\n border : '1px solid rgb(80,80,80)',\n color : 'inherit',\n },\n panel : { border: 'rgb(70,70,70)' },\n indicator: { color: 'rgb(160,160,160)' },\n },\n tab : {\n underBorderFullWidth: false,\n toolbar: { background: '#2a2a2a', border: '#444' },\n button : {\n background: '#3a3a3a',\n border : 'none',\n hover : { background: '#454545', border: 'none' },\n selected : { background: 'rgb(30, 30, 30)', border: 'none' },\n },\n indicator: { color: '#4a9eff' },\n },\n window : {\n shadow : '3px 3px 2px rgba(0, 0, 0, 0.6)',\n snapGlow : '0 0 0 2px rgba(80, 150, 240, 0.8)',\n control : {\n background : 'rgb(30, 30, 30)',\n border : '1px solid transparent',\n shadow : 'none',\n hoverBackground : 'rgb(55, 55, 55)',\n activeBackground: 'rgb(45, 45, 45)',\n },\n header : { background: '#2a2a2a' },\n },\n table : {\n header: {\n background: 'linear-gradient(rgb(70, 70, 70), rgb(50, 50, 50))',\n border: '#555',\n glyph : { color: 'currentColor' },\n },\n row : {\n selected : 'rgba(30, 100, 200, 0.25)',\n selectedBorder: 'inset 0 0 0 1px rgba(30, 100, 200, 0.8)',\n new : 'rgba(70, 200, 70, 0.2)',\n dirty : 'rgba(255, 165, 0, 0.2)',\n stripe : 'rgba(255, 255, 255, 0.045)',\n },\n cell : {\n background : 'transparent',\n readonlyBackground : 'rgba(255, 255, 255, 0.04)',\n requiredEmptyOutlineColor : 'rgba(255, 90, 90, 0.8)',\n color : 'inherit',\n border : 'none',\n editorBorderColor : 'rgba(30, 100, 200, 0.8)',\n },\n resizeHandle: {\n color : 'rgba(255, 255, 255, 0.25)',\n },\n sortBadge: {\n background: 'rgba(255, 255, 255, 0.2)',\n color : 'inherit',\n },\n },\n contextMenu: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n menuBar: {\n // Menu bars share the tool bar's background by default (see toolBar below).\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n button : {\n background : 'transparent',\n hoverBackground: 'rgba(100, 140, 220, 0.15)',\n foreground : 'inherit',\n },\n panel : {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.5)',\n },\n item : {\n hoverBackground: 'rgba(100, 140, 220, 0.2)',\n disabledColor : 'rgb(100, 100, 100)',\n shortcutColor : 'rgb(140, 140, 140)',\n },\n separatorColor: 'rgb(70, 70, 70)',\n },\n statusBar: {\n background: 'rgb(45, 45, 45)',\n color : 'rgb(200, 200, 200)',\n border : 'rgb(70, 70, 70)',\n },\n toolBar: {\n background : 'rgb(45, 45, 45)',\n border : 'rgb(70, 70, 70)',\n separatorColor: 'rgb(70, 70, 70)',\n },\n tooltip: {\n background: 'rgb(60, 60, 45)',\n color : 'rgb(220, 220, 180)',\n border : 'rgb(120, 110, 70)',\n shadow : '1px 2px 4px rgba(0, 0, 0, 0.5)',\n },\n popover: {\n background: 'rgb(50, 50, 55)',\n color : 'rgb(230, 230, 235)',\n border : 'rgb(90, 90, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.55)',\n },\n notification: {\n shadow : '2px 4px 8px rgba(0, 0, 0, 0.4)',\n info : { background: 'rgba(30, 100, 200, 0.4)', border: 'rgb(30, 100, 200)' },\n success: { background: 'rgba(30, 180, 80, 0.4)', border: 'rgb(30, 180, 80)' },\n warning: { background: 'rgba(220, 140, 0, 0.4)', border: 'rgb(220, 140, 0)' },\n error : { background: 'rgba(200, 50, 50, 0.4)', border: 'rgb(200, 50, 50)' },\n },\n validation: {\n error: {\n border : 'rgb(220, 80, 80)',\n tooltip: {\n background: 'rgb(160, 30, 30)',\n color : 'rgb(255, 220, 220)',\n border : 'rgb(120, 20, 20)',\n },\n },\n },\n autoComplete: {\n background: 'rgb(45, 45, 45)',\n border : 'rgb(80, 80, 80)',\n shadow : '2px 4px 8px rgba(0,0,0,0.5)',\n item: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n highlightBackground: 'rgba(100, 140, 220, 0.28)',\n highlightColor : 'rgb(220, 220, 255)',\n disabledColor : 'rgb(100, 100, 100)',\n },\n },\n // Dark defaults track `autoComplete` for the same hover/selected hues so\n // the row chrome stays consistent across the two popover surfaces.\n list: {\n background: 'rgb(40, 40, 40)',\n border : 'rgb(80, 80, 80)',\n row: {\n hoverBackground : 'rgba(100, 140, 220, 0.12)',\n selectedBackground: 'rgba(100, 140, 220, 0.28)',\n selectedColor : 'rgb(220, 220, 255)',\n focusRing : 'rgb(120, 170, 240)',\n disabledColor : 'rgb(100, 100, 100)',\n separator : 'transparent',\n },\n },\n indicator: {\n focus : 'rgb(120, 170, 240)',\n selection: '1px dashed rgb(120, 170, 240)',\n },\n // Dark picker tokens follow the dark `autoComplete.item.*` hue family for\n // chevron-hover consistency with cell hover.\n picker: {\n navForeground: 'var(--ts-ui-text-color)',\n navHoverBackground: 'rgba(120, 170, 255, 0.12)',\n cellDisabledBackground: 'transparent',\n },\n dialog: {\n backdrop: { background: 'rgba(0, 0, 0, 0.65)' },\n border : 'rgb(70, 70, 70)',\n shadow : '4px 8px 24px rgba(0, 0, 0, 0.6)',\n confirm : 'rgb(80, 200, 110)',\n cancel : 'rgb(220, 90, 90)',\n info : { background: 'rgba(30, 100, 200, 0.25)', foreground: 'rgb(60, 130, 220)' },\n affirm : { background: 'rgba(80, 200, 110, 0.25)', foreground: 'rgb(80, 200, 110)' },\n },\n drawer: {\n background: 'var(--ts-ui-body-bg)',\n shadow : '4px 0 24px rgba(0, 0, 0, 0.55)',\n border : 'rgb(70, 70, 70)',\n },\n rail: {\n background: 'var(--ts-ui-body-bg)',\n border : 'rgb(70, 70, 70)',\n shadow : '2px 0 12px rgba(0, 0, 0, 0.45)',\n handle: {\n hoverBackground : 'rgba(120, 170, 240, 0.12)',\n selectedBackground: 'rgba(120, 170, 240, 0.22)',\n },\n },\n spinner: {\n dividerColor: 'rgb(80, 80, 80)',\n },\n progressBar: {\n track : { background: 'rgb(55, 55, 55)' },\n fill : { background: 'rgb(60, 130, 220)' },\n indeterminate: { background: 'rgb(60, 130, 220)' },\n },\n progressSpinner: {\n color : 'rgb(60, 130, 220)',\n backdrop: 'rgba(20, 20, 20, 0.6)',\n },\n drag: {\n ghost: {\n background: 'rgba(60, 60, 60, 0.9)',\n border : 'rgb(100, 100, 100)',\n shadow : '2px 4px 12px rgba(0, 0, 0, 0.6)',\n },\n feedback: {\n valid : { background: 'rgba(30, 180, 80, 0.2)', border: 'rgb(30, 180, 80)' },\n invalid: { background: 'rgba(200, 50, 50, 0.18)', border: 'rgb(200, 50, 50)' },\n },\n reorderIndicator: {\n color: 'rgb(80, 140, 240)',\n },\n dropzone: {\n background : 'rgba(80, 140, 240, 0.12)',\n border : 'rgba(80, 140, 240, 0.45)',\n activeBackground : 'rgba(80, 140, 240, 0.32)',\n invalidBackground: 'rgba(200, 50, 50, 0.32)',\n },\n },\n fileDropZone: {\n background : 'rgba(80, 140, 240, 0.10)',\n border : '2px dashed rgba(80, 140, 240, 0.45)',\n activeBackground: 'rgba(80, 140, 240, 0.24)',\n activeBorder : '2px dashed rgba(80, 140, 240, 0.85)',\n },\n scroll: {\n shadowColor: 'rgba(0, 0, 0, 1)',\n },\n // Okabe–Ito-derived categorical palette, brightened for adequate contrast on\n // a dark background. Light-grey axis/label with a dim grid; the selection\n // ring reuses the theme's blue accent (matching the focus indicator).\n chart: {\n series: [\n '#56B4E9', // sky\n '#E69F00', // orange\n '#00C08B', // green\n '#FF7F4D', // vermilion\n '#E48FC1', // purple\n '#0091D5', // blue\n '#F0E442', // yellow\n '#AAAAAA', // grey\n ],\n axis : 'rgb(176, 176, 176)',\n grid : 'rgb(58, 58, 58)',\n label : 'rgb(192, 192, 192)',\n selection: '#4a9eff',\n },\n});\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Panel, PanelOptions } from \"~/core/Panel.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Form}.\n *\n * @category Core\n */\nexport interface FormOptions extends PanelOptions {\n /**\n * Called after a native form submission is requested — via the submit\n * button, Enter in a field, or `requestSubmit()`. The framework has already\n * called `preventDefault()` on the submit event, so the page will not\n * navigate; the handler owns what submission means.\n */\n onSubmit?: (form: Form) => void;\n}\n\n/**\n * A {@link Panel} that bakes the semantic `<form>` tag and wires the native\n * `submit` event to a single `onSubmit` callback.\n *\n * Use `Form` as the content surface for a group of fields that should submit\n * together — it inherits `Panel`'s 4-pixel insets and `autoScroll` stack, so a\n * tall form in a short area scrolls rather than inflating to content size.\n * Trigger a submission from an external control (e.g. a footer button outside\n * the form) via {@link Form.requestSubmit}, which reaches the browser's native\n * `HTMLFormElement.requestSubmit()` — firing the cancelable `submit` event and\n * running constraint validation — through the `DOM.sink` seam, mirroring how\n * {@link Component.focus} reaches the native `focus()`.\n *\n * @example\n * ```typescript\n * const form = new Form({\n * onSubmit: (f) => console.log('submitted'),\n * });\n * // ...\n * submitButton.on(\"action\", () => form.requestSubmit());\n * ```\n *\n * @category Core\n */\nclass Form<TOptions extends FormOptions = FormOptions> extends Panel<TOptions> {\n\n private _onSubmit: ((form: Form) => void) | null = null;\n\n /**\n * @param options - Optional. Construction-time options applied to the form.\n */\n constructor(options?: TOptions) {\n super(options, { tag: \"form\" } as Partial<TOptions>);\n\n // Wire after super() returns: Event.addListener needs the fully\n // constructed component, and this is the deferred-dispatch site the\n // super-cascade trap requires (never applyOptions).\n this._onSubmit = options?.onSubmit ?? null;\n Event.addListener(this, \"submit\", this.handleSubmit);\n }\n\n /**\n * Handles the native `submit` event: prevents the browser's default\n * navigation and forwards to the `onSubmit` callback, if any.\n *\n * @param e - The native submit event.\n */\n private handleSubmit(e: SubmitEvent): void {\n e.preventDefault();\n this._onSubmit?.(this);\n }\n\n /**\n * Requests a native form submission, firing the cancelable `submit` event\n * and running the browser's constraint validation (unlike `.submit()`,\n * which skips both). No-op if the form is not yet rendered.\n */\n requestSubmit(): void {\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n DOM.sink.requestSubmit(element);\n }\n}\n\nconst FormCallable = callable(Form);\ntype FormCallable<TOptions extends FormOptions = FormOptions> = Form<TOptions>;\nexport {\n Form as _Form,\n FormCallable as Form,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ThemeManager, ModernTheme } from \"~/core/Theme.js\";\n\n/**\n * A {@link Component} that wraps the page's `<body>` element.\n *\n * Mount a top-level layout in one call:\n * ```\n * Body.init({ layoutManager: Fit(), components: [shell] });\n * ```\n *\n * Once mounted, reach the singleton again with `Body.getInstance()` — to add a\n * further child, read the layout manager, or attach a listener.\n *\n * @category Core\n */\nexport class Body extends Component {\n\n private static readonly INSTANCE: Body = new Body();\n\n /**\n * Returns the singleton Body instance — the accessor for reaching the body\n * *after* it is mounted: adding a further child, reading its layout\n * manager, or attaching a listener. To mount a top-level layout in one\n * call, use `Body.init` instead.\n *\n * @returns The single shared Body component for this page.\n */\n static getInstance() {\n return this.INSTANCE;\n }\n\n /**\n * Applies an options bag to the singleton Body and returns it — the\n * ergonomic entry point for mounting a top-level layout in one call:\n * `Body.init({ layoutManager: Fit(), components: [shell] })`. Only the\n * supplied fields are dispatched (it delegates to\n * `Component.applyOptions`), so the body's viewport-size tracking and\n * theme set up at construction are preserved.\n *\n * @param options - Component options to apply (layout manager, children, …).\n *\n * @returns The singleton Body instance, for chaining.\n */\n static init(options: ComponentOptions = {}): Body {\n this.INSTANCE.applyOptions(options);\n\n return this.INSTANCE;\n }\n\n private constructor() {\n super({ tag: \"body\" });\n\n this.init();\n\n this.setBackgroundColor(\"var(--ts-ui-body-bg, rgb(241, 241, 241))\");\n\n ThemeManager.setTheme(ModernTheme);\n }\n\n /**\n * Returns the document body element.\n *\n * @returns The `<body>` HTMLElement.\n */\n getElement() {\n return DOM.source.getBody();\n }\n\n /**\n * Initializes the body size from the viewport and registers a resize listener to keep it in sync.\n *\n * @returns This component, for method chaining.\n */\n protected init(): this {\n super.init();\n\n this.setSize(DOM.source.getViewportSize());\n this.clearInsets();\n\n Event.addViewportListener(this, \"resize\", this._onViewportResize);\n\n return this;\n }\n\n /**\n * Bound viewport-resize handler. Reads the current viewport extent on\n * each fire (DOM `resize` events carry no payload) and writes it\n * through the typed setter.\n */\n private _onViewportResize = (): void => {\n this.setSize(DOM.source.getViewportSize());\n };\n\n /**\n * Overrides {@link Component.clampsToContentSize} to `false`: the body *is*\n * the viewport, so its size must track {@link Util.getViewportSize} exactly\n * and let oversized content overflow (the page scrolls / a child `Panel`\n * scrolls internally) rather than inflating the body up to its\n * content-derived minimum. With the `Component` default (`true`),\n * {@link Component.setSize} ran the viewport extent through\n * {@link Component.clampHeight}, which floored it to `getMinSize()` — the\n * tall content's minimum — so once that minimum was measured the body could\n * never shrink back below its content when the viewport shrank.\n *\n * @returns `false`, so size clamping uses the body's own explicit\n * constraints only, not its content-derived ones.\n */\n protected clampsToContentSize(): boolean {\n return false;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { LayerManager } from \"~/core/LayerManager.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\n\n/**\n * A physical-key chord. `code` is a `KeyboardEvent.code` value (layout-independent).\n *\n * @category Core\n */\nexport interface FocusHistoryKeyCombo {\n code: string;\n ctrl?: boolean;\n alt?: boolean;\n shift?: boolean;\n meta?: boolean;\n}\n\n/**\n * Options for {@link FocusHistory.enable} / {@link FocusHistory.configure}.\n *\n * @category Core\n */\nexport interface FocusHistoryOptions {\n /** Max entries retained; oldest dropped past this. Default 50. */\n maxSize?: number;\n /** Back accelerator. Default `Alt+[` (`{ code: \"BracketLeft\", alt: true }`). */\n back?: FocusHistoryKeyCombo;\n /** Forward accelerator. Default `Alt+]` (`{ code: \"BracketRight\", alt: true }`). */\n forward?: FocusHistoryKeyCombo;\n}\n\n/**\n * The sole custom event name fired by {@link FocusHistory}.\n *\n * @category Core\n */\nexport type FocusHistoryEvent = \"change\";\n\n/**\n * Payload of the `\"change\"` event: the navigability of the trail after the change.\n *\n * @category Core\n */\nexport interface FocusHistoryChange {\n canGoBack: boolean;\n canGoForward: boolean;\n}\n\n// 50: a working session's focus trail rarely exceeds a few dozen stops; caps\n// memory at 50 handle numbers while leaving generous back-depth.\nconst DEFAULT_MAX_ENTRIES: number = 50;\n// Alt+[ / Alt+]: editor-style \"navigate back/forward\"; no default browser\n// action (unlike Alt+Left/Right = browser history); layout-independent via code.\nconst DEFAULT_BACK_COMBO: FocusHistoryKeyCombo = { code: \"BracketLeft\", alt: true };\nconst DEFAULT_FORWARD_COMBO: FocusHistoryKeyCombo = { code: \"BracketRight\", alt: true };\n\n// Sentinel used to register the service's viewport listeners — see\n// LayerManager's identical `_listenerOwner` pattern. `FocusHistory` has no DOM\n// element of its own, so a stable, otherwise-unused `Component` owns them.\nconst _owner: Component = new Component();\nconst _listeners = new ListenerBag<FocusHistoryEvent>();\n\n// Chronological trail, oldest first. Entries are bare `Handle`s (not\n// `Component`s) because focus frequently lands on an element with no 1:1\n// component (an input inside a Text, a raw button).\nlet _entries: Handle[] = [];\n// Current position in `_entries`; -1 when the trail is empty.\nlet _index: number = -1;\nlet _enabled: boolean = false;\n// Re-entrancy guard: true for the duration of a service-driven `DOM.sink.focus`\n// call, so the synchronous `focusin` it triggers is not recorded as a new move.\nlet _navigating: boolean = false;\nlet _maxSize: number = DEFAULT_MAX_ENTRIES;\nlet _back: FocusHistoryKeyCombo = DEFAULT_BACK_COMBO;\nlet _forward: FocusHistoryKeyCombo = DEFAULT_FORWARD_COMBO;\n\n/**\n * Whether `handle` still resolves to a connected element. A GC-collected weak\n * handle throws on resolve inside the DOM seam; that is treated as stale too.\n */\nfunction isLive(handle: Handle): boolean {\n try {\n return DOM.source.isConnected(handle);\n } catch {\n return false;\n }\n}\n\n/**\n * Drops every stale (no-longer-connected) entry from the trail, keeping\n * `_index` pointed at the nearest surviving entry at or before its old\n * position (or -1 if nothing survived there). Run before every navigation\n * and every `canGo*` query so those never act on a dead entry.\n */\nfunction pruneStale(): void {\n const kept: Handle[] = [];\n let newIndex = -1;\n\n for (let i = 0; i < _entries.length; i++) {\n const handle = _entries[i];\n\n if (isLive(handle)) {\n kept.push(handle);\n\n if (i <= _index) {\n newIndex = kept.length - 1;\n }\n }\n }\n\n _entries = kept;\n _index = newIndex;\n}\n\n/** Computes the current navigability and notifies `\"change\"` listeners. */\nfunction fireChange(): void {\n const change: FocusHistoryChange = {\n canGoBack: _index > 0,\n canGoForward: _index < _entries.length - 1,\n };\n\n _listeners.fire(\"change\", change);\n}\n\n/**\n * Appends `handle` to the trail (deduping a repeat of the current entry and\n * truncating any forward branch), advances `_index`, and fires `\"change\"`.\n */\nfunction record(handle: Handle): void {\n if (_index >= 0 && _entries[_index] === handle) {\n return;\n }\n\n _entries.length = _index + 1;\n _entries.push(handle);\n\n while (_entries.length > _maxSize) {\n _entries.shift();\n }\n\n _index = _entries.length - 1;\n fireChange();\n}\n\n/** Re-focuses `handle` under the re-entrancy guard, then fires `\"change\"`. */\nfunction focusEntry(handle: Handle): void {\n _navigating = true;\n DOM.sink.focus(handle);\n _navigating = false;\n fireChange();\n}\n\n/**\n * Prunes stale entries, then moves `_index` by `direction` and re-focuses the\n * entry there, if one exists.\n *\n * @returns True if focus moved.\n */\nfunction navigate(direction: -1 | 1): boolean {\n pruneStale();\n\n const target = _index + direction;\n\n if (target < 0 || target >= _entries.length) {\n return false;\n }\n\n _index = target;\n focusEntry(_entries[_index]);\n\n return true;\n}\n\n/** Whether a `KeyboardEvent` matches a configured combo. */\nfunction matchesCombo(e: KeyboardEvent, combo: FocusHistoryKeyCombo): boolean {\n return e.code === combo.code &&\n e.altKey === !!combo.alt && e.ctrlKey === !!combo.ctrl &&\n e.shiftKey === !!combo.shift && e.metaKey === !!combo.meta;\n}\n\n/** Document `focusin` handler: records the newly-focused element. */\nfunction onFocusIn(e: FocusEvent): void {\n if (!_enabled || _navigating) {\n return;\n }\n\n if (!DOM.source.isElement(e.target)) {\n return;\n }\n\n record(DOM.source.intern(e.target));\n}\n\n/**\n * Document `keydown` handler: drives `back()`/`forward()` on the configured\n * combos, suppressed while a modal layer is on top so the accelerator does\n * not fight the modal's own focus trap.\n */\nfunction onKeyDown(e: KeyboardEvent): void {\n if (!_enabled) {\n return;\n }\n\n const direction: -1 | 1 | 0 = matchesCombo(e, _back) ? -1 : matchesCombo(e, _forward) ? 1 : 0;\n\n if (direction === 0) {\n return;\n }\n\n const top = LayerManager.getTopLayer();\n\n if (top && top.getDismissMode() === \"modal\") {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n navigate(direction);\n}\n\n/**\n * Global focus-trail navigation service: records the chronological order in\n * which elements receive keyboard focus across the document and drives an\n * accelerator that walks the trail backward and forward, like browser\n * back/forward but for keyboard focus. Opt-in — call {@link enable} to start\n * recording; nothing auto-starts it.\n *\n * @category Core\n */\nexport namespace FocusHistory {\n /**\n * Installs the `focusin` + `keydown` listeners, seeds the trail with the\n * current active element (if any), and begins recording. Idempotent —\n * calling it again while already enabled only applies `options`.\n *\n * @param options - Optional `maxSize` / combo overrides, applied via\n * {@link configure} before enabling.\n */\n export function enable(options?: FocusHistoryOptions): void {\n if (options) {\n configure(options);\n }\n\n if (_enabled) {\n return;\n }\n\n _enabled = true;\n\n Event.addViewportListener(_owner, \"focusin\", onFocusIn);\n Event.addViewportListener(_owner, \"keydown\", onKeyDown);\n\n const active = DOM.source.getActiveElement();\n\n if (active !== null) {\n record(active);\n }\n }\n\n /**\n * Removes the listeners and stops recording. Preserves the trail —\n * re-enabling resumes from where it left off. Idempotent.\n */\n export function disable(): void {\n if (!_enabled) {\n return;\n }\n\n _enabled = false;\n _navigating = false;\n\n Event.removeViewportListener(_owner, \"focusin\", onFocusIn);\n Event.removeViewportListener(_owner, \"keydown\", onKeyDown);\n }\n\n /** Whether the service is currently observing. */\n export function isEnabled(): boolean {\n return _enabled;\n }\n\n /**\n * Updates `maxSize` / combos without toggling enablement. Only the\n * supplied fields change.\n *\n * @param options - The fields to update.\n */\n export function configure(options: FocusHistoryOptions): void {\n if (options.maxSize !== undefined) {\n _maxSize = options.maxSize;\n }\n\n if (options.back !== undefined) {\n _back = options.back;\n }\n\n if (options.forward !== undefined) {\n _forward = options.forward;\n }\n }\n\n /**\n * Re-focuses the previous live entry, skipping and dropping any stale\n * ones encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function back(): boolean {\n return navigate(-1);\n }\n\n /**\n * Re-focuses the next live entry, skipping and dropping any stale ones\n * encountered along the way.\n *\n * @returns True if focus moved.\n */\n export function forward(): boolean {\n return navigate(1);\n }\n\n /**\n * Whether a live entry exists before the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoBack(): boolean {\n pruneStale();\n\n return _index > 0;\n }\n\n /**\n * Whether a live entry exists after the current position. Prunes stale\n * entries as a side effect, so a stale-only direction never reports true.\n */\n export function canGoForward(): boolean {\n pruneStale();\n\n return _index < _entries.length - 1;\n }\n\n /** Empties the trail and fires `\"change\"` with both flags false. */\n export function clear(): void {\n _entries = [];\n _index = -1;\n fireChange();\n }\n\n /**\n * Subscribes to trail-navigability changes, fired after every recorded\n * focus move and after every `back()` / `forward()` navigation.\n *\n * @param event - Always `\"change\"`.\n * @param listener - Invoked with the trail's navigability after the change.\n */\n export function on(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.add(event, listener);\n }\n\n /**\n * Unsubscribes a `\"change\"` listener.\n *\n * @param event - Always `\"change\"`.\n * @param listener - The exact callback reference passed to {@link on}.\n */\n export function off(event: \"change\", listener: (change: FocusHistoryChange) => void): void {\n _listeners.remove(event, listener);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from '~/core/BaseObject.js';\nimport { ModelRecord } from '~/data/ModelRecord.js';\nimport { Bindable, BindingAccessors } from '~/core/Bindable.js';\nimport { Component } from '~/core/Component.js';\nimport { ListenerBag } from '~/core/ListenerBag.js';\nimport { ValidationRule, FieldValidationConfig } from '~/validation/ValidationRule.js';\nimport { FieldDecorator } from '~/validation/FieldDecorator.js';\nimport { applyRule } from '~/validation/Validator.js';\n\n/**\n * String-literal union of events emitted by {@link Binding}.\n *\n * @category Data\n */\nexport type BindingEvent = \"change\" | \"commit\" | \"reject\" | \"beforerecord\";\n\ninterface BoundEntry {\n accessors: BindingAccessors<any>;\n active: boolean;\n}\n\n/**\n * Listener consulted before a record change takes effect.\n *\n * Receives the *next* record (or `null`) and returns `false` to cancel the\n * change. Any other return value (`true`, `undefined`, …) allows it.\n *\n * @category Data\n */\nexport type BeforeRecordListener = (next: ModelRecord | null) => boolean;\n\n/**\n * Synchronises a {@link ModelRecord} with a set of UI components.\n *\n * Components are registered with {@link bind}, either as {@link Bindable} implementors\n * (short form) or via explicit accessor callbacks (long form). Once a record is loaded\n * via {@link setRecord}, every bound component is populated from the record's fields.\n * Conversely, whenever a component's value changes, the record is updated automatically.\n *\n * @example Short form — component implements Bindable\n * ```typescript\n * const binding = new Binding()\n * .bind('name', nameField)\n * .bind('active', activeCheckbox)\n * .bind('role', roleCombo);\n *\n * binding.setRecord(record);\n * ```\n *\n * @example Long form — explicit accessors for any component\n * ```typescript\n * const binding = new Binding()\n * .bind('name', myWidget, {\n * get: () => myWidget.getValue(),\n * set: (v) => myWidget.setValue(v),\n * listen: (fn) => myWidget.on(\"change\", fn),\n * });\n * ```\n *\n * @category Data\n */\nexport class Binding extends BaseObject {\n\n private _record: ModelRecord | null = null;\n private _entries: Map<string, BoundEntry> = new Map();\n private _listeners: ListenerBag<BindingEvent> = new ListenerBag<BindingEvent>();\n private _validationConfigs: Map<string, FieldValidationConfig> = new Map();\n private _globalValidateOnChange: boolean = false;\n private _loading: boolean = false;\n\n // ── Registration ────────────────────────────────────────────────────────\n\n /**\n * Registers a field binding using a component that implements {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - A component implementing the {@link Bindable} interface.\n */\n bind<T>(fieldName: string, component: Bindable<T>): this;\n\n /**\n * Registers a field binding using explicit accessor callbacks.\n * Use this overload for components that do not implement {@link Bindable}.\n *\n * @param fieldName - The record field to bind to.\n * @param component - Any object (used only as a placeholder for the overload).\n * @param accessors - Getter, setter, and change-listener callbacks.\n */\n bind<T>(fieldName: string, component: object, accessors: BindingAccessors<T>): this;\n\n bind<T>(fieldName: string, component: Bindable<T> | object, accessors?: BindingAccessors<T>): this {\n this.unbind(fieldName);\n\n const acc: BindingAccessors<any> = accessors ?? {\n get: () => (component as Bindable<T>).getValue(),\n set: (v: T) => (component as Bindable<T>).setValue(v),\n listen: (fn) => (component as Bindable<T>).on(\"binding\", fn),\n };\n\n const entry: BoundEntry = { accessors: acc, active: true };\n this._entries.set(fieldName, entry);\n\n acc.listen(() => {\n if (this._loading) {\n return;\n }\n\n if (!entry.active || !this._record) {\n return;\n }\n\n const value = acc.get();\n this._record.set(fieldName, value);\n\n this.emit(\"change\", fieldName, value);\n\n this._validateFieldIfLive(fieldName);\n });\n\n if (this._record) {\n acc.set(this._record.get(fieldName));\n }\n\n return this;\n }\n\n /**\n * Removes the binding for the given field.\n * The change listener previously attached to the component becomes a no-op.\n *\n * @param fieldName - The field whose binding should be removed.\n */\n unbind(fieldName: string): this {\n const entry = this._entries.get(fieldName);\n if (entry) {\n entry.active = false;\n\n this._entries.delete(fieldName);\n }\n\n return this;\n }\n\n // ── Record management ────────────────────────────────────────────────────\n\n /**\n * Loads a record into the binding. All registered components are immediately\n * populated with the corresponding field values. Pass `null` to clear the binding.\n *\n * Before any state mutation, every `on(\"beforerecord\", fn)` listener is\n * consulted; if any returns `false` the\n * call is a complete no-op (no validation reset, no field population) and\n * `this` is returned unchanged.\n *\n * @param record - The record to bind, or `null` to detach.\n */\n setRecord(record: ModelRecord | null): this {\n for (const fn of this._listeners.get(\"beforerecord\") as BeforeRecordListener[]) {\n if (fn(record) === false) {\n return this;\n }\n }\n\n this._record = record;\n\n this.clearValidation();\n\n if (!record) {\n return this;\n }\n\n this._loading = true;\n\n try {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(record.get(fieldName));\n }\n } finally {\n this._loading = false;\n }\n\n for (const [fieldName] of this._validationConfigs) {\n this._validateFieldIfLive(fieldName);\n }\n\n return this;\n }\n\n /**\n * Returns the currently bound record, or `null` if none is loaded.\n */\n getRecord(): ModelRecord | null {\n return this._record;\n }\n\n // ── Commit / reject ──────────────────────────────────────────────────────\n\n /**\n * Commits the current record, clearing its dirty and new flags.\n * Fires all registered commit listeners.\n */\n commit(): this {\n this._record?.commit();\n\n this.emit(\"commit\");\n\n return this;\n }\n\n /**\n * Rejects all changes on the current record and re-syncs every component\n * from the reverted field values. Fires all registered reject listeners.\n * Also clears any active validation error decorations.\n */\n reject(): void {\n this._record?.reject();\n\n if (this._record) {\n for (const [fieldName, entry] of this._entries) {\n entry.accessors.set(this._record.get(fieldName));\n }\n }\n\n this.clearValidation();\n\n this.emit(\"reject\");\n }\n\n // ── Listeners ────────────────────────────────────────────────────────────\n\n /**\n * Registers a listener for one of this binding's events.\n *\n * @param event - `\"change\"` fires whenever any bound component changes a\n * field value, receiving `(fieldName, value)`. `\"commit\"` fires after\n * {@link commit}. `\"reject\"` fires after {@link reject}.\n * `\"beforerecord\"` is consulted before {@link setRecord} mutates state;\n * returning `false` vetoes the call as a complete no-op.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This binding, for method chaining.\n *\n * @remarks `\"beforerecord\"` veto semantics: iteration stops on the first\n * `false`; if any listener vetoes, {@link setRecord} returns without\n * modifying any state. Returning `true` — or anything other than\n * `false`, including `undefined` — allows the change. Async\n * confirmation must be handled at the call site — {@link setRecord}\n * stays synchronous. A listener that itself calls {@link setRecord}\n * re-enters the same veto loop, which is supported but discouraged.\n * `null` is a valid `next` value (it represents a clear); a listener\n * that only wants to guard non-clear switches must short-circuit\n * `next === null` itself.\n */\n on(event: \"change\", listener: (fieldName: string, value: unknown) => void): this;\n on(event: \"commit\", listener: () => void): this;\n on(event: \"reject\", listener: () => void): this;\n on(event: \"beforerecord\", listener: BeforeRecordListener): this;\n on(event: BindingEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This binding, for method chaining.\n */\n off(event: BindingEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order. Internal use only — external callers route\n * dispatch through {@link commit} / {@link reject} / {@link setRecord}.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"change\", fieldName: string, value: unknown): void;\n protected emit(event: \"commit\"): void;\n protected emit(event: \"reject\"): void;\n protected emit(event: BindingEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n // ── Validation ───────────────────────────────────────────────────────────\n\n /**\n * Attaches one or more validation rules to a bound field.\n *\n * @param fieldName - The field name registered with {@link bind}.\n * @param component - The Component instance to wrap with a {@link FieldDecorator} on error.\n * @param rules - One or more {@link ValidationRule} objects to apply to this field.\n *\n * @returns this, for chaining.\n */\n addValidation(fieldName: string, component: Component, rules: ValidationRule | ValidationRule[]): this {\n const ruleArray = Array.isArray(rules) ? rules : [rules];\n\n this._validationConfigs.set(fieldName, {\n rules : ruleArray,\n component,\n validateOnChange: false,\n decorator : null,\n });\n\n return this;\n }\n\n /**\n * Removes all validation rules for a field and clears any existing error decoration.\n *\n * @param fieldName - The field whose validation should be removed.\n *\n * @returns this, for chaining.\n */\n removeValidation(fieldName: string): this {\n const config = this._validationConfigs.get(fieldName);\n\n if (config?.decorator) {\n config.decorator.clearError();\n }\n\n this._validationConfigs.delete(fieldName);\n\n return this;\n }\n\n /**\n * Runs all registered validation rules against the current field values.\n * Applies or clears {@link FieldDecorator} error state for each validated field.\n *\n * @returns true if all fields pass; false if any field fails.\n */\n validate(): boolean {\n let allValid = true;\n\n for (const [fieldName] of this._validationConfigs) {\n const valid = this._validateField(fieldName);\n\n if (!valid) {\n allValid = false;\n }\n }\n\n return allValid;\n }\n\n /**\n * Enables or disables live validation (validation on every field change).\n *\n * @param enabled - true to validate on every change event; false for explicit-only.\n */\n setValidateOnChange(enabled: boolean): this {\n this._globalValidateOnChange = enabled;\n\n return this;\n }\n\n /**\n * Returns whether live validation is globally enabled.\n *\n * @returns true if live validation is active.\n */\n getValidateOnChange(): boolean {\n return this._globalValidateOnChange;\n }\n\n /**\n * Clears all error decorations without re-running rules.\n * Called automatically by {@link reject}.\n */\n clearValidation(): this {\n for (const [, config] of this._validationConfigs) {\n if (config.decorator) {\n config.decorator.clearError();\n }\n }\n\n return this;\n }\n\n /**\n * Validates a single field and updates its decorator.\n *\n * @param fieldName - The field to validate.\n *\n * @returns true if the field passes all rules.\n */\n private _validateField(fieldName: string): boolean {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return true;\n }\n\n const entry = this._entries.get(fieldName);\n const value = entry ? entry.accessors.get() : undefined;\n\n for (const rule of config.rules) {\n const result = applyRule(rule, value);\n\n if (result.valid) {\n continue;\n }\n\n if (!config.decorator) {\n const parent = config.component.getParentComponent();\n\n if (parent) {\n config.decorator = new FieldDecorator(config.component, parent);\n }\n }\n\n config.decorator?.showError(result.message);\n\n return false;\n }\n\n config.decorator?.clearError();\n\n return true;\n }\n\n /**\n * Calls {@link _validateField} only if live validation is active for this field.\n *\n * @param fieldName - The field to conditionally validate.\n */\n private _validateFieldIfLive(fieldName: string): void {\n const config = this._validationConfigs.get(fieldName);\n\n if (!config) {\n return;\n }\n\n const live = config.validateOnChange || this._globalValidateOnChange;\n\n if (live) {\n this._validateField(fieldName);\n }\n }\n}\n"],"mappings":"opBAkBA,IAAa,EAAsB,EAAY,EAAW,CACtD,YAAa,QACb,KAAa,CAAE,MAAO,cAAe,EACrC,KAAa,CAAE,WAAY,oBAAqB,EAChD,OAAa,CAAE,MAAO,OAAQ,EAC9B,OAAa,CACT,WAAY,0DACZ,OAAY,qBACZ,OAAY,mCACZ,YAAa,CACT,WAAY,oBAChB,EACA,QAAY,CACR,WAAY,qBACZ,WAAY,0DACZ,OAAY,qCAChB,EACA,MAAY,CACR,WAAY,UACZ,WAAY,0DACZ,OAAY,mCAChB,EACA,KAAY,CACR,MAAS,CACL,WAAY,sBACZ,OAAY,8BAChB,EACA,QAAS,CACL,WAAY,sBACZ,OAAY,wCACZ,OAAY,8BAChB,CACJ,CACJ,EACA,OAAc,CACV,SAAU,CACN,WAAY,qBACZ,OAAY,wBAChB,CACJ,EACA,MAAQ,CACJ,WAAa,qBACb,OAAa,+BACb,YAAa,8BACjB,EACA,KAAQ,CACJ,WAAoB,qBACpB,OAAoB,qBACpB,MAAoB,kBACpB,mBAAoB,qBACpB,cAAoB,qBACpB,UAAoB,oBACpB,OAAU,CACN,mBAAoB,qBACpB,kBAAoB,oBACpB,gBAAoB,oBACxB,EACA,OAAU,CACN,gBAAuB,qBACvB,sBAAuB,oBACvB,gBAAuB,oBAC3B,EACA,SAAU,CACN,WAAyB,qBACzB,mBAAyB,oBACzB,wBAAyB,qBACzB,WAAyB,oBAC7B,EACA,MAAU,CACN,WAAoB,qBACpB,mBAAoB,oBACpB,SAAoB,oBACxB,CACJ,EACA,OAAQ,CAAE,WAAY,SAAU,EAChC,SAAU,CACN,MAAQ,CAAE,WAAY,UAAW,KAAM,MAAO,EAC9C,OAAQ,CAAE,MAAO,kBAAmB,CACxC,EACA,UAAW,CACP,OAAW,6BACX,OAAW,CACP,WAAY,qDACZ,OAAY,6BACZ,MAAY,SAChB,EACA,MAAW,CAAE,OAAQ,kBAAmB,EACxC,UAAW,CAAE,MAAO,kBAAmB,CAC3C,EACA,IAAQ,CACJ,QAAS,CAAE,WAAY,OAAY,OAAQ,SAAU,EACrD,OAAS,CACL,WAAY,0DACZ,OAAY,OACZ,MAAY,CAAE,WAAY,0DAA2D,OAAQ,MAAO,EACpG,SAAY,CAAE,WAAY,0DAA2D,OAAQ,MAAO,CACxG,EACA,UAAW,CAAE,MAAO,SAAU,CAClC,EACA,OAAQ,CACJ,OAAc,iCACd,SAAc,oCACd,QAAc,CACV,WAAkB,0DAClB,OAAkB,+BAClB,OAAkB,mCAClB,gBAAkB,0DAClB,iBAAkB,yDACtB,EACA,OAAc,CAAE,WAAY,MAAO,CACvC,EACA,MAAQ,CACJ,OAAQ,CACJ,WAAY,0DACZ,OAAQ,QACR,MAAQ,CAAE,MAAO,cAAe,CACpC,EACA,IAAQ,CACJ,SAAgB,2BAChB,eAAgB,0CAChB,IAAgB,0BAChB,MAAgB,0BAChB,OAAgB,sBACpB,EACA,KAAQ,CACJ,WAA4B,cAC5B,mBAA4B,sBAC5B,0BAA4B,yBAC5B,MAA4B,UAC5B,OAA4B,OAC5B,kBAA4B,yBAChC,EACA,aAAc,CACV,MAAQ,oBACZ,EACA,UAAW,CACP,WAAY,sBACZ,MAAY,SAChB,CACJ,EACA,YAAa,CACT,WAAgB,qBAChB,OAAgB,qBAChB,OAAgB,kCAChB,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,oBACrB,EACA,eAAgB,oBACpB,EACA,QAAS,CAEL,WAAgB,qBAChB,OAAgB,qBAChB,OAAgB,CACZ,WAAiB,cACjB,gBAAiB,2BACjB,WAAiB,SACrB,EACA,MAAgB,CACZ,WAAY,qBACZ,OAAY,qBACZ,OAAY,iCAChB,EACA,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,qBACjB,cAAiB,oBACrB,EACA,eAAgB,oBACpB,EACA,UAAW,CACP,WAAY,qBACZ,MAAY,kBACZ,OAAY,oBAChB,EACA,QAAS,CACL,WAAgB,qBAChB,OAAgB,qBAChB,eAAgB,oBACpB,EACA,QAAS,CACL,WAAY,qBACZ,MAAY,eACZ,OAAY,qBACZ,OAAY,gCAChB,EACA,QAAS,CACL,WAAY,qBACZ,MAAY,eACZ,OAAY,qBACZ,OAAY,kCAChB,EACA,aAAc,CACV,OAAS,kCACT,KAAS,CAAE,WAAY,4BAA8B,OAAQ,mBAAqB,EAClF,QAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,EAClF,QAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,EAClF,MAAS,CAAE,WAAY,4BAA8B,OAAQ,kBAAqB,CACtF,EACA,WAAY,CACR,MAAO,CACH,OAAS,mBACT,QAAS,CACL,WAAY,mBACZ,MAAY,qBACZ,OAAY,kBAChB,CACJ,CACJ,EACA,aAAc,CACV,WAAY,qBACZ,OAAY,qBACZ,OAAY,+BACZ,KAAM,CACF,gBAAqB,2BACrB,oBAAqB,2BACrB,eAAqB,UACrB,cAAqB,oBACzB,CACJ,EAMA,KAAM,CACF,WAAY,qBACZ,OAAY,qBACZ,IAAK,CACD,gBAAoB,2BACpB,mBAAoB,2BACpB,cAAoB,UACpB,UAAoB,oBACpB,cAAoB,qBACpB,UAAoB,aACxB,CACJ,EACA,UAAW,CACP,MAAW,oBACX,UAAW,+BACf,EAIA,OAAQ,CACJ,cAAwB,0BACxB,mBAAwB,2BACxB,uBAAwB,aAC5B,EACA,OAAQ,CACJ,SAAU,CAAE,WAAY,qBAAsB,EAC9C,OAAU,qBACV,OAAU,mCACV,QAAU,mBACV,OAAU,mBACV,KAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,EACpF,OAAU,CAAE,WAAY,0BAA4B,WAAY,kBAAoB,CACxF,EACA,OAAQ,CACJ,WAAY,uBACZ,OAAY,iCACZ,OAAY,oBAChB,EACA,KAAM,CACF,WAAY,uBACZ,OAAY,qBACZ,OAAY,iCACZ,OAAQ,CACJ,gBAAoB,2BACpB,mBAAoB,0BACxB,CACJ,EACA,QAAS,CACL,aAAc,oBAClB,EACA,YAAa,CACT,MAAe,CAAE,WAAY,oBAAqB,EAClD,KAAe,CAAE,WAAY,mBAAoB,EACjD,cAAe,CAAE,WAAY,mBAAoB,CACrD,EACA,gBAAiB,CACb,MAAU,oBACV,SAAU,0BACd,EACA,KAAM,CACF,MAAO,CACH,WAAY,2BACZ,OAAY,qBACZ,OAAY,kCAChB,EACA,SAAU,CACN,MAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAoB,EAC9E,QAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAmB,CACjF,EACA,iBAAkB,CACd,MAAO,mBACX,EACA,SAAU,CACN,WAAmB,2BACnB,OAAmB,2BACnB,iBAAmB,2BACnB,kBAAmB,yBACvB,CACJ,EACA,aAAc,CACV,WAAkB,2BAClB,OAAkB,sCAClB,iBAAkB,2BAClB,aAAkB,qCACtB,EACA,OAAQ,CACJ,YAAa,kBACjB,EAIA,MAAO,CACH,OAAQ,CACJ,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACJ,EACA,KAAW,qBACX,KAAW,qBACX,MAAW,kBACX,UAAW,SACf,CACJ,CAAC,EC/UY,EAAmB,EAAY,EAAW,CACnD,YAAa,OACb,KAAa,CAAE,MAAO,oBAAqB,EAC3C,KAAa,CAAE,WAAY,iBAAkB,EAC7C,OAAa,CAAE,MAAO,iBAAkB,EACxC,OAAa,CACT,WAAY,oDACZ,OAAY,kBACZ,OAAY,mCACZ,YAAa,CACT,WAAY,oBAChB,EACA,QAAY,CACR,WAAY,qBACZ,WAAY,oDACZ,OAAY,oCAChB,EACA,MAAY,CACR,WAAY,UACZ,WAAY,oDACZ,OAAY,mCAChB,EACA,KAAY,CACR,MAAS,CACL,WAAY,4BACZ,OAAY,2BAChB,EACA,QAAS,CACL,WAAY,4BACZ,OAAY,wCACZ,OAAY,2BAChB,CACJ,CACJ,EACA,OAAc,CACV,SAAU,CACN,WAAY,kBACZ,OAAY,wBAChB,CACJ,EACA,MAAQ,CACJ,WAAa,kBACb,OAAa,+BACb,YAAa,8BACjB,EACA,KAAQ,CACJ,WAAoB,kBACpB,OAAoB,qBACpB,MAAoB,qBACpB,mBAAoB,kBACpB,cAAoB,qBACpB,UAAoB,qBACpB,OAAU,CACN,mBAAoB,kBACpB,kBAAoB,qBACpB,gBAAoB,oBACxB,EACA,OAAU,CACN,gBAAuB,kBACvB,sBAAuB,qBACvB,gBAAuB,oBAC3B,EACA,SAAU,CACN,WAAyB,kBACzB,mBAAyB,qBACzB,wBAAyB,qBACzB,WAAyB,iBAC7B,EACA,MAAU,CACN,WAAoB,kBACpB,mBAAoB,qBACpB,SAAoB,iBACxB,CACJ,EACA,OAAQ,CAAE,WAAY,MAAO,EAC7B,SAAU,CACN,MAAQ,CAAE,WAAY,OAAQ,KAAM,MAAO,EAC3C,OAAQ,CAAE,MAAO,kBAAmB,CACxC,EACA,UAAW,CACP,OAAW,0BACX,OAAW,CACP,WAAY,+CACZ,OAAY,0BACZ,MAAY,SAChB,EACA,MAAW,CAAE,OAAQ,eAAgB,EACrC,UAAW,CAAE,MAAO,kBAAmB,CAC3C,EACA,IAAQ,CACJ,qBAAsB,GACtB,QAAS,CAAE,WAAY,UAAW,OAAQ,MAAO,EACjD,OAAS,CACL,WAAY,UACZ,OAAY,OACZ,MAAY,CAAE,WAAY,UAAoB,OAAQ,MAAO,EAC7D,SAAY,CAAE,WAAY,kBAAmB,OAAQ,MAAO,CAChE,EACA,UAAW,CAAE,MAAO,SAAU,CAClC,EACA,OAAY,CACR,OAAc,iCACd,SAAc,oCACd,QAAc,CACV,WAAkB,kBAClB,OAAkB,wBAClB,OAAkB,OAClB,gBAAkB,kBAClB,iBAAkB,iBACtB,EACA,OAAc,CAAE,WAAY,SAAU,CAC1C,EACA,MAAY,CACR,OAAQ,CACJ,WAAY,oDACZ,OAAQ,OACR,MAAQ,CAAE,MAAO,cAAe,CACpC,EACA,IAAQ,CACJ,SAAgB,2BAChB,eAAgB,0CAChB,IAAgB,yBAChB,MAAgB,yBAChB,OAAgB,4BACpB,EACA,KAAQ,CACJ,WAA4B,cAC5B,mBAA4B,4BAC5B,0BAA4B,yBAC5B,MAA4B,UAC5B,OAA4B,OAC5B,kBAA4B,yBAChC,EACA,aAAc,CACV,MAAQ,2BACZ,EACA,UAAW,CACP,WAAY,2BACZ,MAAY,SAChB,CACJ,EACA,YAAa,CACT,WAAgB,kBAChB,OAAgB,kBAChB,OAAgB,iCAChB,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,oBACrB,EACA,eAAgB,iBACpB,EACA,QAAS,CAEL,WAAgB,kBAChB,OAAgB,kBAChB,OAAgB,CACZ,WAAiB,cACjB,gBAAiB,4BACjB,WAAiB,SACrB,EACA,MAAgB,CACZ,WAAY,kBACZ,OAAY,kBACZ,OAAY,gCAChB,EACA,KAAgB,CACZ,gBAAiB,2BACjB,cAAiB,qBACjB,cAAiB,oBACrB,EACA,eAAgB,iBACpB,EACA,UAAW,CACP,WAAY,kBACZ,MAAY,qBACZ,OAAY,iBAChB,EACA,QAAS,CACL,WAAgB,kBAChB,OAAgB,kBAChB,eAAgB,iBACpB,EACA,QAAS,CACL,WAAY,kBACZ,MAAY,qBACZ,OAAY,oBACZ,OAAY,gCAChB,EACA,QAAS,CACL,WAAY,kBACZ,MAAY,qBACZ,OAAY,mBACZ,OAAY,kCAChB,EACA,aAAc,CACV,OAAS,iCACT,KAAS,CAAE,WAAY,0BAA4B,OAAQ,mBAAqB,EAChF,QAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,EAChF,QAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,EAChF,MAAS,CAAE,WAAY,yBAA4B,OAAQ,kBAAqB,CACpF,EACA,WAAY,CACR,MAAO,CACH,OAAS,mBACT,QAAS,CACL,WAAY,mBACZ,MAAY,qBACZ,OAAY,kBAChB,CACJ,CACJ,EACA,aAAc,CACV,WAAY,kBACZ,OAAY,kBACZ,OAAY,8BACZ,KAAM,CACF,gBAAqB,4BACrB,oBAAqB,4BACrB,eAAqB,qBACrB,cAAqB,oBACzB,CACJ,EAGA,KAAM,CACF,WAAY,kBACZ,OAAY,kBACZ,IAAK,CACD,gBAAoB,4BACpB,mBAAoB,4BACpB,cAAoB,qBACpB,UAAoB,qBACpB,cAAoB,qBACpB,UAAoB,aACxB,CACJ,EACA,UAAW,CACP,MAAW,qBACX,UAAW,+BACf,EAGA,OAAQ,CACJ,cAAwB,0BACxB,mBAAwB,4BACxB,uBAAwB,aAC5B,EACA,OAAQ,CACJ,SAAU,CAAE,WAAY,qBAAsB,EAC9C,OAAU,kBACV,OAAU,kCACV,QAAU,oBACV,OAAU,mBACV,KAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,EACpF,OAAU,CAAE,WAAY,2BAA4B,WAAY,mBAAoB,CACxF,EACA,OAAQ,CACJ,WAAY,uBACZ,OAAY,iCACZ,OAAY,iBAChB,EACA,KAAM,CACF,WAAY,uBACZ,OAAY,kBACZ,OAAY,iCACZ,OAAQ,CACJ,gBAAoB,4BACpB,mBAAoB,2BACxB,CACJ,EACA,QAAS,CACL,aAAc,iBAClB,EACA,YAAa,CACT,MAAe,CAAE,WAAY,iBAAkB,EAC/C,KAAe,CAAE,WAAY,mBAAoB,EACjD,cAAe,CAAE,WAAY,mBAAoB,CACrD,EACA,gBAAiB,CACb,MAAU,oBACV,SAAU,uBACd,EACA,KAAM,CACF,MAAO,CACH,WAAY,wBACZ,OAAY,qBACZ,OAAY,iCAChB,EACA,SAAU,CACN,MAAS,CAAE,WAAY,yBAA2B,OAAQ,kBAAoB,EAC9E,QAAS,CAAE,WAAY,0BAA2B,OAAQ,kBAAmB,CACjF,EACA,iBAAkB,CACd,MAAO,mBACX,EACA,SAAU,CACN,WAAmB,2BACnB,OAAmB,2BACnB,iBAAmB,2BACnB,kBAAmB,yBACvB,CACJ,EACA,aAAc,CACV,WAAkB,2BAClB,OAAkB,sCAClB,iBAAkB,2BAClB,aAAkB,qCACtB,EACA,OAAQ,CACJ,YAAa,kBACjB,EAIA,MAAO,CACH,OAAQ,CACJ,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACJ,EACA,KAAW,qBACX,KAAW,kBACX,MAAW,qBACX,UAAW,SACf,CACJ,CAAC,EC5SK,KAAN,cAA+D,CAAgB,CAE3E,UAAmD,KAKnD,YAAY,EAAoB,CAC5B,MAAM,EAAS,CAAE,IAAK,MAAO,CAAsB,EAKnD,KAAK,UAAY,GAAS,UAAY,KACtC,EAAM,YAAY,KAAM,SAAU,KAAK,YAAY,CACvD,CAQA,aAAqB,EAAsB,CACvC,EAAE,eAAe,EACjB,KAAK,YAAY,IAAI,CACzB,CAOA,eAAsB,CAClB,IAAM,EAAU,KAAK,WAAW,EAE3B,GAIL,EAAI,KAAK,cAAc,CAAO,CAClC,CACJ,EAEM,EAAe,EAAS,IAAI,ECtErB,EAAb,MAAa,aAAa,CAAU,CAEhC,OAAwB,SAAiB,IAAI,KAU7C,OAAO,aAAc,CACjB,OAAO,KAAK,QAChB,CAcA,OAAO,KAAK,EAA4B,CAAC,EAAS,CAG9C,OAFA,KAAK,SAAS,aAAa,CAAO,EAE3B,KAAK,QAChB,CAEA,aAAsB,CAClB,MAAM,CAAE,IAAK,MAAO,CAAC,EAErB,KAAK,KAAK,EAEV,KAAK,mBAAmB,0CAA0C,EAElE,EAAa,SAAS,CAAW,CACrC,CAOA,YAAa,CACT,OAAO,EAAI,OAAO,QAAQ,CAC9B,CAOA,MAAuB,CAQnB,OAPA,MAAM,KAAK,EAEX,KAAK,QAAQ,EAAI,OAAO,gBAAgB,CAAC,EACzC,KAAK,YAAY,EAEjB,EAAM,oBAAoB,KAAM,SAAU,KAAK,iBAAiB,EAEzD,IACX,CAOA,sBAAwC,CACpC,KAAK,QAAQ,EAAI,OAAO,gBAAgB,CAAC,CAC7C,EAgBA,qBAAyC,CACrC,MAAO,EACX,CACJ,EC5DM,EAA8B,GAG9B,EAA8C,CAAE,KAAM,cAAgB,IAAK,EAAK,EAChF,EAA8C,CAAE,KAAM,eAAgB,IAAK,EAAK,EAKhF,EAAoB,IAAI,EACxB,EAAa,IAAI,EAKnB,EAAqB,CAAC,EAEtB,EAAiB,GACjB,EAAoB,GAGpB,EAAuB,GACvB,EAAmB,EACnB,EAAiC,EACjC,EAAiC,EAMrC,SAAS,OAAO,EAAyB,CACrC,GAAI,CACA,OAAO,EAAI,OAAO,YAAY,CAAM,CACxC,MAAQ,CACJ,MAAO,EACX,CACJ,CAQA,SAAS,YAAmB,CACxB,IAAM,EAAiB,CAAC,EACpB,EAAW,GAEf,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACtC,IAAM,EAAS,EAAS,GAEpB,OAAO,CAAM,IACb,EAAK,KAAK,CAAM,EAEZ,GAAK,IACL,EAAW,EAAK,OAAS,GAGrC,CAEA,EAAW,EACX,EAAS,CACb,CAGA,SAAS,YAAmB,CACxB,IAAM,EAA6B,CAC/B,UAAc,EAAS,EACvB,aAAc,EAAS,EAAS,OAAS,CAC7C,EAEA,EAAW,KAAK,SAAU,CAAM,CACpC,CAMA,SAAS,OAAO,EAAsB,CAC9B,QAAU,GAAK,EAAS,KAAY,GAOxC,KAHA,EAAS,OAAS,EAAS,EAC3B,EAAS,KAAK,CAAM,EAEb,EAAS,OAAS,GACrB,EAAS,MAAM,EAGnB,EAAS,EAAS,OAAS,EAC3B,WAAW,CAJQ,CAKvB,CAGA,SAAS,WAAW,EAAsB,CACtC,EAAc,GACd,EAAI,KAAK,MAAM,CAAM,EACrB,EAAc,GACd,WAAW,CACf,CAQA,SAAS,SAAS,EAA4B,CAC1C,WAAW,EAEX,IAAM,EAAS,EAAS,EASxB,OAPI,EAAS,GAAK,GAAU,EAAS,OAC1B,IAGX,EAAS,EACT,WAAW,EAAS,EAAO,EAEpB,GACX,CAGA,SAAS,aAAa,EAAkB,EAAsC,CAC1E,OAAO,EAAE,OAAS,EAAM,MACpB,EAAE,SAAW,CAAC,CAAC,EAAM,KAAO,EAAE,UAAY,CAAC,CAAC,EAAM,MAClD,EAAE,WAAa,CAAC,CAAC,EAAM,OAAS,EAAE,UAAY,CAAC,CAAC,EAAM,IAC9D,CAGA,SAAS,UAAU,EAAqB,CAChC,CAAC,GAAY,GAIZ,EAAI,OAAO,UAAU,EAAE,MAAM,GAIlC,OAAO,EAAI,OAAO,OAAO,EAAE,MAAM,CAAC,CACtC,CAOA,SAAS,UAAU,EAAwB,CACvC,GAAI,CAAC,EACD,OAGJ,IAAM,EAAwB,aAAa,EAAG,CAAK,EAAI,GAAK,gBAAa,EAAG,CAAQ,EAEpF,GAAI,IAAc,EACd,OAGJ,IAAM,EAAM,EAAa,YAAY,EAEjC,GAAO,EAAI,eAAe,IAAM,UAIpC,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAClB,SAAS,CAAS,EACtB,CAWO,IAAA,eASI,SAAS,OAAO,EAAqC,CAKxD,GAJI,GACA,UAAU,CAAO,EAGjB,EACA,OAGJ,EAAW,GAEX,EAAM,oBAAoB,EAAQ,UAAW,SAAS,EACtD,EAAM,oBAAoB,EAAQ,UAAW,SAAS,EAEtD,IAAM,EAAS,EAAI,OAAO,iBAAiB,EAEvC,IAAW,MACX,OAAO,CAAM,CAErB,iBAMO,SAAS,SAAgB,CACvB,IAIL,EAAW,GACX,EAAc,GAEd,EAAM,uBAAuB,EAAQ,UAAW,SAAS,EACzD,EAAM,uBAAuB,EAAQ,UAAW,SAAS,EAC7D,mBAGO,SAAS,WAAqB,CACjC,OAAO,CACX,uBAQO,SAAS,UAAU,EAAoC,CACtD,EAAQ,UAAY,IAAA,KACpB,EAAW,EAAQ,SAGnB,EAAQ,OAAS,IAAA,KACjB,EAAQ,EAAQ,MAGhB,EAAQ,UAAY,IAAA,KACpB,EAAW,EAAQ,QAE3B,uBAQO,SAAS,MAAgB,CAC5B,OAAO,SAAS,EAAE,CACtB,aAQO,SAAS,SAAmB,CAC/B,OAAO,SAAS,CAAC,CACrB,mBAMO,SAAS,WAAqB,CAGjC,OAFA,WAAW,EAEJ,EAAS,CACpB,uBAMO,SAAS,cAAwB,CAGpC,OAFA,WAAW,EAEJ,EAAS,EAAS,OAAS,CACtC,6BAGO,SAAS,OAAc,CAC1B,EAAW,CAAC,EACZ,EAAS,GACT,WAAW,CACf,eASO,SAAS,GAAG,EAAiB,EAAsD,CACtF,EAAW,IAAI,EAAO,CAAQ,CAClC,SAQO,SAAS,IAAI,EAAiB,EAAsD,CACvF,EAAW,OAAO,EAAO,CAAQ,CACrC,aACH,AAAA,IAAA,CAAA,CAAD,ECrTA,IAAa,QAAb,cAA6B,CAAW,CAEpC,QAAsC,KACtC,SAA4C,IAAI,IAChD,WAAgD,IAAI,EACpD,mBAAiE,IAAI,IACrE,wBAA2C,GAC3C,SAA4B,GAsB5B,KAAQ,EAAmB,EAAiC,EAAuC,CAC/F,KAAK,OAAO,CAAS,EAErB,IAAM,EAA6B,GAAa,CAC5C,QAAe,EAA0B,SAAS,EAClD,IAAS,GAAU,EAA0B,SAAS,CAAC,EACvD,OAAS,GAAQ,EAA0B,GAAG,UAAW,CAAE,CAC/D,EAEM,EAAoB,CAAE,UAAW,EAAK,OAAQ,EAAK,EAwBzD,OAvBA,KAAK,SAAS,IAAI,EAAW,CAAK,EAElC,EAAI,WAAa,CAKb,GAJI,KAAK,UAIL,CAAC,EAAM,QAAU,CAAC,KAAK,QACvB,OAGJ,IAAM,EAAQ,EAAI,IAAI,EACtB,KAAK,QAAQ,IAAI,EAAW,CAAK,EAEjC,KAAK,KAAK,SAAU,EAAW,CAAK,EAEpC,KAAK,qBAAqB,CAAS,CACvC,CAAC,EAEG,KAAK,SACL,EAAI,IAAI,KAAK,QAAQ,IAAI,CAAS,CAAC,EAGhC,IACX,CAQA,OAAO,EAAyB,CAC5B,IAAM,EAAQ,KAAK,SAAS,IAAI,CAAS,EAOzC,OANI,IACA,EAAM,OAAS,GAEf,KAAK,SAAS,OAAO,CAAS,GAG3B,IACX,CAeA,UAAU,EAAkC,CACxC,IAAK,IAAM,KAAM,KAAK,WAAW,IAAI,cAAc,EAC/C,GAAI,EAAG,CAAM,IAAM,GACf,OAAO,KAQf,GAJA,KAAK,QAAU,EAEf,KAAK,gBAAgB,EAEjB,CAAC,EACD,OAAO,KAGX,KAAK,SAAW,GAEhB,GAAI,CACA,IAAK,GAAM,CAAC,EAAW,KAAU,KAAK,SAClC,EAAM,UAAU,IAAI,EAAO,IAAI,CAAS,CAAC,CAEjD,QAAU,CACN,KAAK,SAAW,EACpB,CAEA,IAAK,GAAM,CAAC,KAAc,KAAK,mBAC3B,KAAK,qBAAqB,CAAS,EAGvC,OAAO,IACX,CAKA,WAAgC,CAC5B,OAAO,KAAK,OAChB,CAQA,QAAe,CAKX,OAJA,KAAK,SAAS,OAAO,EAErB,KAAK,KAAK,QAAQ,EAEX,IACX,CAOA,QAAe,CAGX,GAFA,KAAK,SAAS,OAAO,EAEjB,KAAK,QACL,IAAK,GAAM,CAAC,EAAW,KAAU,KAAK,SAClC,EAAM,UAAU,IAAI,KAAK,QAAQ,IAAI,CAAS,CAAC,EAIvD,KAAK,gBAAgB,EAErB,KAAK,KAAK,QAAQ,CACtB,CA+BA,GAAG,EAAuB,EAA0B,CAGhD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAWA,IAAI,EAAqB,EAA0B,CAG/C,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAaA,KAAe,EAAqB,GAAG,EAA0B,CAC7D,KAAK,WAAW,KAAK,EAAO,GAAG,CAAO,CAC1C,CAaA,cAAc,EAAmB,EAAsB,EAAgD,CACnG,IAAM,EAAY,MAAM,QAAQ,CAAK,EAAI,EAAQ,CAAC,CAAK,EASvD,OAPA,KAAK,mBAAmB,IAAI,EAAW,CACnC,MAAkB,EAClB,YACA,iBAAkB,GAClB,UAAkB,IACtB,CAAC,EAEM,IACX,CASA,iBAAiB,EAAyB,CACtC,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAQpD,OANI,GAAQ,WACR,EAAO,UAAU,WAAW,EAGhC,KAAK,mBAAmB,OAAO,CAAS,EAEjC,IACX,CAQA,UAAoB,CAChB,IAAI,EAAW,GAEf,IAAK,GAAM,CAAC,KAAc,KAAK,mBACb,KAAK,eAAe,CAE7B,IACD,EAAW,IAInB,OAAO,CACX,CAOA,oBAAoB,EAAwB,CAGxC,MAFA,MAAK,wBAA0B,EAExB,IACX,CAOA,qBAA+B,CAC3B,OAAO,KAAK,uBAChB,CAMA,iBAAwB,CACpB,IAAK,GAAM,EAAG,KAAW,KAAK,mBACtB,EAAO,WACP,EAAO,UAAU,WAAW,EAIpC,OAAO,IACX,CASA,eAAuB,EAA4B,CAC/C,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAEpD,GAAI,CAAC,EACD,MAAO,GAGX,IAAM,EAAQ,KAAK,SAAS,IAAI,CAAS,EACnC,EAAQ,EAAQ,EAAM,UAAU,IAAI,EAAI,IAAA,GAE9C,IAAK,IAAM,KAAQ,EAAO,MAAO,CAC7B,IAAM,EAAS,EAAU,EAAM,CAAK,EAEhC,MAAO,MAIX,IAAI,CAAC,EAAO,UAAW,CACnB,IAAM,EAAS,EAAO,UAAU,mBAAmB,EAE/C,IACA,EAAO,UAAY,IAAI,EAAe,EAAO,UAAW,CAAM,EAEtE,CAIA,OAFA,EAAO,WAAW,UAAU,EAAO,OAAO,EAEnC,EAJP,CAKJ,CAIA,OAFA,EAAO,WAAW,WAAW,EAEtB,EACX,CAOA,qBAA6B,EAAyB,CAClD,IAAM,EAAS,KAAK,mBAAmB,IAAI,CAAS,EAE/C,IAIQ,EAAO,kBAAoB,KAAK,0BAGzC,KAAK,eAAe,CAAS,CAErC,CACJ"}
|
package/dist/lib/layout.es.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,o as t}from"./Position-
|
|
1
|
+
import{a as e,o as t}from"./Position-DJKB0N3l.js";import{c as n,d as r,f as i,l as a,u as o}from"./Component-Bs6TvaGZ.js";import{t as s}from"./Fit-CUS1JXy3.js";import{t as c}from"./BoxLayout-8ryMD4j5.js";import{t as l}from"./HBox-BWMf9h6r.js";import{o as u}from"./LayoutSizes-XdhpAOmc.js";import{t as d}from"./Border-5Ki2DCWz.js";import{t as f}from"./LayoutConstraints-CHI2lhPd.js";import{n as p}from"./VBox-CdV9VGxR.js";import{a as m,n as h,r as g,t as _}from"./LayoutSerialization-C_zcwaN3.js";import{n as v,r as y,t as b}from"./GridConstraints-CzC0w4i-.js";import{t as x}from"./Grid-D8luwRPI.js";import{t as S}from"./Card-AKIUAWYS.js";var Anchor=class extends a{constructor(e){super(),e&&this.applyOptions(e)}resolve(e,t){if(e!==void 0)return typeof e==`number`?e:t*e.percent/100}resolveAxis(e,t,n,r,i,a,o){if(e!==void 0&&t!==void 0){let n=Math.max(0,r-e-t);return{start:o+e,extent:n}}let s=n??i;return e===void 0?t===void 0?{start:a,extent:s}:{start:o+r-t-s,extent:s}:{start:o+e,extent:s}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getContentInsets(),r=n.getLeft(),i=n.getTop();for(let n of e.getLaidOutComponents()){let e=this.getLayoutConstraints(n),a=n.getPreferredSize(),o=n.getSize(),s=a?.width??o?.width??0,c=a?.height??o?.height??0,l=this.resolveAxis(this.resolve(e?.left,t.width),this.resolve(e?.right,t.width),this.resolve(e?.width,t.width),t.width,s,n.getX(),r),u=this.resolveAxis(this.resolve(e?.top,t.height),this.resolve(e?.bottom,t.height),this.resolve(e?.height,t.height),t.height,c,n.getY(),i);this.commitBounds(n,l.start,u.start,l.extent,u.extent)}}},C=i(Anchor),AnchorConstraints=class extends f{left;right;top;bottom;width;height;constructor(){super()}},FlowLayout=class extends a{_spacing=5;_lineSpacing=5;_uniform=`none`;_align=`start`;_itemAlign=`start`;_justify=`start`;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.spacing!==void 0&&this.setComponentSpacing(e.spacing),e.lineSpacing!==void 0&&this.setLineSpacing(e.lineSpacing),e.uniform!==void 0&&this.setUniform(e.uniform),e.align!==void 0&&this.setAlign(e.align),e.itemAlign!==void 0&&this.setItemAlign(e.itemAlign),e.justify!==void 0&&this.setJustify(e.justify)}getComponentSpacing(){return this._spacing||0}setComponentSpacing(e){return this._spacing=e||0,this}getLineSpacing(){return this._lineSpacing||0}setLineSpacing(e){return this._lineSpacing=e||0,this}getUniform(){return this._uniform}setUniform(e){return this._uniform=e,this}getAlign(){return this._align}setAlign(e){return this._align=e,this}getItemAlign(){return this._itemAlign}setItemAlign(e){return this._itemAlign=e,this}getJustify(){return this._justify}setJustify(e){return this._justify=e,this}isUniformWidth(){return this._uniform===`width`||this._uniform===`both`}isUniformHeight(){return this._uniform===`height`||this._uniform===`both`}computeUniformExtents(e){let t=0,n=0;for(let r of e){let e=this.clampedPreferredSize(r);t=Math.max(t,e.width),n=Math.max(n,e.height)}return{width:t,height:n}}clampedPreferredSize(e){let t=e.getPreferredSize(),n=e.getMinSize(),r=e.getMaxSize(),i=t?t.width:0,a=t?t.height:0;return n&&(i=Math.max(i,n.width),a=Math.max(a,n.height)),r&&(i=Math.min(i,r.width),a=Math.min(a,r.height)),{width:i,height:a}}alignLead(e,t){let n=Math.max(0,t-e);return this._align===`center`?n/2:this._align===`end`?n:0}crossOffset(e,t,n,r,i){switch(this._itemAlign){case`center`:return Math.max(0,(t-e)/2);case`end`:return Math.max(0,t-e);case`baseline`:return r===null?0:n===null?this.nullChildY(e,r,i):r-n;default:return 0}}justifyGaps(e,t,n,r){let i=t+r*Math.max(0,e-1);if(this._justify===`start`||e<2||i>=n)return{lead:0,gap:r};let a=n-t;if(this._justify===`between`)return{lead:0,gap:a/(e-1)};let o=a/e;return{lead:o/2,gap:o}}},HFlow=class extends FlowLayout{getPreferredSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=this.isUniformWidth(),i=this.isUniformHeight(),a=r||i?this.computeUniformExtents(n):{width:0,height:0},o=t.left+t.right,s=[],c=[];for(let e of n){let t=e.getPreferredSize();t&&(r||(o+=t.width),s.push(t.height),c.push(e.getBaseline()))}r&&(o+=n.length*a.width),o+=this._spacing*Math.max(0,n.length-1);let l=i?a.height:this.computeRowHeight(s,c);return l+=t.top+t.bottom,{width:o,height:l}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=0,i=[],a=[];for(let e of n){let t=e.getMinSize();t&&(r=Math.max(r,t.width),i.push(t.height),a.push(e.getBaseline()))}let o=t.left+t.right+r,s=this.computeRowHeight(i,a);return s+=t.top+t.bottom,{width:o,height:s}}getMaxSize(){let n=this.getContainer();if(!n)return null;let r=n.getPerimeterSize(),i=n.getLaidOutComponents(),a=this.isUniformWidth(),o=a?this.computeUniformExtents(i):{width:0,height:0},s=r.left+r.right,c=0,l=!1,u=!1;for(let e of i){let n=e.getMaxSize();if(!n){a||(l=!0),u=!0;continue}a||(t(n.width)?l=!0:s+=n.width),t(n.height)?u=!0:c=Math.max(c,n.height)}return a&&(s+=i.length*o.width),s+=this._spacing*Math.max(0,i.length-1),c+=r.top+r.bottom,{width:l?e:s,height:u?e:c}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getLaidOutComponents(),r=e.getContentInsets(),i=this.getComponentSpacing(),a=this.getLineSpacing(),o=this.isUniformWidth(),s=this.isUniformHeight(),c=o||s?this.computeUniformExtents(n):{width:0,height:0},l=this.groupIntoRows(n,t.width,r.getTop(),i,a,o,s,c);this.placeRows(l,r.getLeft(),t.width,i),this.reserveContentFrame()}groupIntoRows(e,t,n,r,i,a,o,s){let c=[],l=n,u=null;for(let n of e){let e=this.clampedPreferredSize(n),d=a?s.width:e.width,f=o?s.height:e.height;u&&u.contentWidth+r+d>t&&(l+=u.rowHeight+i,u=null),u||(u={cells:[],contentWidth:0,rowHeight:0,y:l},c.push(u));let p=u.cells.length===0?Math.min(d,t):d;u.contentWidth+=u.cells.length===0?p:r+p,u.cells.push({component:n,width:p,height:f,baseline:n.getBaseline()}),u.rowHeight=Math.max(u.rowHeight,f)}return c}placeRows(e,t,n,i){for(let a of e){let e=a.cells.map(e=>e.height),o=a.cells.map(e=>e.baseline),{rowAscent:s,rowDescent:c}=this.computeRowMetrics(e,o),{lead:l,gap:u}=this.justifyGaps(a.cells.length,this.cellsMainExtent(a),n,i),d=t+(this._justify===`start`?this.alignLead(a.contentWidth,n):0)+l;for(let e of a.cells){let t=a.y+this.crossOffset(e.height,a.rowHeight,e.baseline,s,c);this.placeComponent(e.component,d,t,e.width,e.height,r.NONE),d+=e.width+u}}}cellsMainExtent(e){return e.cells.reduce((e,t)=>e+t.width,0)}},w=i(HFlow),VFlow=class extends FlowLayout{getPreferredSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=this.isUniformWidth(),i=this.isUniformHeight(),a=r||i?this.computeUniformExtents(n):{width:0,height:0},o=t.top+t.bottom,s=0;for(let e of n){let t=e.getPreferredSize();t&&(i||(o+=t.height),s=Math.max(s,t.width))}i&&(o+=n.length*a.height),o+=this._spacing*Math.max(0,n.length-1);let c=r?a.width:s;return c+=t.left+t.right,{width:c,height:o}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents(),r=0,i=0;for(let e of n){let t=e.getMinSize();t&&(r=Math.max(r,t.height),i=Math.max(i,t.width))}return{width:t.left+t.right+i,height:t.top+t.bottom+r}}getMaxSize(){let n=this.getContainer();if(!n)return null;let r=n.getPerimeterSize(),i=n.getLaidOutComponents(),a=this.isUniformHeight(),o=a?this.computeUniformExtents(i):{width:0,height:0},s=r.top+r.bottom,c=0,l=!1,u=!1;for(let e of i){let n=e.getMaxSize();if(!n){a||(u=!0),l=!0;continue}a||(t(n.height)?u=!0:s+=n.height),t(n.width)?l=!0:c=Math.max(c,n.width)}return a&&(s+=i.length*o.height),s+=this._spacing*Math.max(0,i.length-1),c+=r.left+r.right,{width:l?e:c,height:u?e:s}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getLaidOutComponents(),r=e.getContentInsets(),i=this.getComponentSpacing(),a=this.getLineSpacing(),o=this.isUniformWidth(),s=this.isUniformHeight(),c=o||s?this.computeUniformExtents(n):{width:0,height:0},l=this.groupIntoColumns(n,t.height,r.getLeft(),i,a,o,s,c);this.placeColumns(l,r.getTop(),t.height,i),this.reserveContentFrame()}groupIntoColumns(e,t,n,r,i,a,o,s){let c=[],l=n,u=null;for(let n of e){let e=this.clampedPreferredSize(n),d=a?s.width:e.width,f=o?s.height:e.height;u&&u.contentHeight+r+f>t&&(l+=u.columnWidth+i,u=null),u||(u={cells:[],contentHeight:0,columnWidth:0,x:l},c.push(u));let p=u.cells.length===0?Math.min(f,t):f;u.contentHeight+=u.cells.length===0?p:r+p,u.cells.push({component:n,width:d,height:p,baseline:null}),u.columnWidth=Math.max(u.columnWidth,d)}return c}placeColumns(e,t,n,i){for(let a of e){let{lead:e,gap:o}=this.justifyGaps(a.cells.length,this.cellsMainExtent(a),n,i),s=t+(this._justify===`start`?this.alignLead(a.contentHeight,n):0)+e;for(let e of a.cells){let t=a.x+this.crossOffset(e.width,a.columnWidth,null,null,0);this.placeComponent(e.component,t,s,e.width,e.height,r.NONE),s+=e.height+o}}}cellsMainExtent(e){return e.cells.reduce((e,t)=>e+t.height,0)}},T=i(VFlow);export{n as Absolute,y as Accordion,v as AccordionConstraints,C as Anchor,AnchorConstraints,o as AnchorType,d as Border,c as BoxLayout,S as Card,g as DockRegion,r as FillType,s as Fit,FlowLayout,x as Grid,b as GridConstraints,l as HBox,w as HFlow,f as LayoutConstraints,a as LayoutManager,m as Split,u as Tab,p as VBox,T as VFlow,_ as restoreLayout,h as serializeLayout};
|
|
2
2
|
//# sourceMappingURL=layout.es.js.map
|