@jimka/typescript-ui 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/{AbstractBooleanInput-C3O4kv7_.js → AbstractBooleanInput-DSwKBAic.js} +2 -2
- package/dist/lib/{AbstractBooleanInput-C3O4kv7_.js.map → AbstractBooleanInput-DSwKBAic.js.map} +1 -1
- package/dist/lib/{AbstractInput-DFWniHqq.js → AbstractInput-BmWGJTs1.js} +2 -2
- package/dist/lib/{AbstractInput-DFWniHqq.js.map → AbstractInput-BmWGJTs1.js.map} +1 -1
- package/dist/lib/{AnchorConstraints-CSUcj8Wx.js → AnchorConstraints-CVrMP9rz.js} +2 -2
- package/dist/lib/{AnchorConstraints-CSUcj8Wx.js.map → AnchorConstraints-CVrMP9rz.js.map} +1 -1
- package/dist/lib/{AnimatedDropdown-e9urCXK1.js → AnimatedDropdown-DKas40B-.js} +2 -2
- package/dist/lib/{AnimatedDropdown-e9urCXK1.js.map → AnimatedDropdown-DKas40B-.js.map} +1 -1
- package/dist/lib/Border-Bz29z-_7.js +2 -0
- package/dist/lib/Border-Bz29z-_7.js.map +1 -0
- package/dist/lib/Button-bjpWruNc.js +2 -0
- package/dist/lib/{Button-B36rBMKC.js.map → Button-bjpWruNc.js.map} +1 -1
- package/dist/lib/{Card-P8iUH2-C.js → Card-BdfbvOD_.js} +2 -2
- package/dist/lib/{Card-P8iUH2-C.js.map → Card-BdfbvOD_.js.map} +1 -1
- package/dist/lib/ComboBox-CBw2VLLN.js +2 -0
- package/dist/lib/ComboBox-CBw2VLLN.js.map +1 -0
- package/dist/lib/Component-DHqrPwAw.js +2 -0
- package/dist/lib/Component-DHqrPwAw.js.map +1 -0
- package/dist/lib/Container-CAQpj4yb.js +2 -0
- package/dist/lib/{Container-xUbHk6l_.js.map → Container-CAQpj4yb.js.map} +1 -1
- package/dist/lib/{DOM-BeR95tE8.js → DOM-67StIm5G.js} +2 -2
- package/dist/lib/DOM-67StIm5G.js.map +1 -0
- package/dist/lib/DragChain-CYGuT7OA.js +2 -0
- package/dist/lib/DragChain-CYGuT7OA.js.map +1 -0
- package/dist/lib/DragManager-CHWCe3-8.js +2 -0
- package/dist/lib/DragManager-CHWCe3-8.js.map +1 -0
- package/dist/lib/{FieldDecorator-BaTGfKiW.js → FieldDecorator-CgAGcqCk.js} +2 -2
- package/dist/lib/{FieldDecorator-BaTGfKiW.js.map → FieldDecorator-CgAGcqCk.js.map} +1 -1
- package/dist/lib/{Fit-E-EIZv1k.js → Fit-DIYt2aQB.js} +2 -2
- package/dist/lib/{Fit-E-EIZv1k.js.map → Fit-DIYt2aQB.js.map} +1 -1
- package/dist/lib/Glyph-CeAIWyPB.js +2 -0
- package/dist/lib/Glyph-CeAIWyPB.js.map +1 -0
- package/dist/lib/{Grid-BXS2T8MT.js → Grid-ViA0joow.js} +2 -2
- package/dist/lib/{Grid-BXS2T8MT.js.map → Grid-ViA0joow.js.map} +1 -1
- package/dist/lib/GridConstraints-B1rxCw9B.js +2 -0
- package/dist/lib/GridConstraints-B1rxCw9B.js.map +1 -0
- package/dist/lib/Header-mKaqgfat.js +2 -0
- package/dist/lib/Header-mKaqgfat.js.map +1 -0
- package/dist/lib/IconText-BqwXA82-.js +2 -0
- package/dist/lib/IconText-BqwXA82-.js.map +1 -0
- package/dist/lib/{LayoutSerialization-D1OHmxSB.js → LayoutSerialization-D82UtnDD.js} +2 -2
- package/dist/lib/{LayoutSerialization-D1OHmxSB.js.map → LayoutSerialization-D82UtnDD.js.map} +1 -1
- package/dist/lib/LayoutSizes-DG9aW9k6.js +2 -0
- package/dist/lib/LayoutSizes-DG9aW9k6.js.map +1 -0
- package/dist/lib/List-CUntS8ux.js +2 -0
- package/dist/lib/List-CUntS8ux.js.map +1 -0
- package/dist/lib/MemoryStore-DT6iWWco.js.map +1 -1
- package/dist/lib/Menu-B_-SQj72.js +2 -0
- package/dist/lib/Menu-B_-SQj72.js.map +1 -0
- package/dist/lib/{MenuButton-Bjm1OyB-.js → MenuButton-C79l8Ysf.js} +2 -2
- package/dist/lib/{MenuButton-Bjm1OyB-.js.map → MenuButton-C79l8Ysf.js.map} +1 -1
- package/dist/lib/{Panel-D9lTLGqP.js → Panel-D2X33qR6.js} +2 -2
- package/dist/lib/{Panel-D9lTLGqP.js.map → Panel-D2X33qR6.js.map} +1 -1
- package/dist/lib/Position-Ck_KD4cR.js +2 -0
- package/dist/lib/Position-Ck_KD4cR.js.map +1 -0
- package/dist/lib/{ProgressSpinner-glv-29eK.js → ProgressSpinner-DCyq02pd.js} +2 -2
- package/dist/lib/{ProgressSpinner-glv-29eK.js.map → ProgressSpinner-DCyq02pd.js.map} +1 -1
- package/dist/lib/{RadioButton-R4S3c9WD.js → RadioButton-BJIAQkII.js} +2 -2
- package/dist/lib/{RadioButton-R4S3c9WD.js.map → RadioButton-BJIAQkII.js.map} +1 -1
- package/dist/lib/{RovingTabIndex-Dgt01LOE.js → RovingTabIndex-DFJyoveq.js} +2 -2
- package/dist/lib/{RovingTabIndex-Dgt01LOE.js.map → RovingTabIndex-DFJyoveq.js.map} +1 -1
- package/dist/lib/Scrollbar-CSFK-Y57.js +2 -0
- package/dist/lib/Scrollbar-CSFK-Y57.js.map +1 -0
- package/dist/lib/Slider-C-kQQYCj.js +2 -0
- package/dist/lib/Slider-C-kQQYCj.js.map +1 -0
- package/dist/lib/{Spacer-B57i2-_G.js → Spacer-D159iJy9.js} +2 -2
- package/dist/lib/{Spacer-B57i2-_G.js.map → Spacer-D159iJy9.js.map} +1 -1
- package/dist/lib/TabButton-CHkXBgCj.js +2 -0
- package/dist/lib/TabButton-CHkXBgCj.js.map +1 -0
- package/dist/lib/{Text-Bni4icFY.js → Text-D5pg7taZ.js} +2 -2
- package/dist/lib/{Text-Bni4icFY.js.map → Text-D5pg7taZ.js.map} +1 -1
- package/dist/lib/Tooltip-DzK6LxUt.js +3 -0
- package/dist/lib/{Tooltip-BUy6uFKN.js.map → Tooltip-DzK6LxUt.js.map} +1 -1
- package/dist/lib/VBox-BNegDPs_.js +2 -0
- package/dist/lib/VBox-BNegDPs_.js.map +1 -0
- package/dist/lib/VirtualScroller-zQr-vKrO.js +2 -0
- package/dist/lib/VirtualScroller-zQr-vKrO.js.map +1 -0
- package/dist/lib/component/button.es.js +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 +2 -2
- 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/layout.es.js.map +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 +1 -1
- package/dist/lib/selectionsEqual-4r5R7pTK.js +2 -0
- package/dist/lib/selectionsEqual-4r5R7pTK.js.map +1 -0
- package/dist/lib/types/component/button/TabCloseButton.d.ts +1 -1
- package/dist/lib/types/component/container/CollapseButton.d.ts +1 -1
- package/dist/lib/types/component/container/DialogBackdrop.d.ts +1 -1
- package/dist/lib/types/component/container/MenuItem.d.ts +4 -0
- package/dist/lib/types/component/container/MenuSeparator.d.ts +1 -1
- package/dist/lib/types/component/container/Scrollbar.d.ts +1 -0
- package/dist/lib/types/component/container/SplitGutter.d.ts +2 -2
- package/dist/lib/types/component/container/StatusBar.d.ts +1 -1
- package/dist/lib/types/component/container/VirtualScroller.d.ts +1 -0
- package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
- package/dist/lib/types/component/diagram/DiagramNode.d.ts +1 -1
- package/dist/lib/types/component/display/Canvas.d.ts +8 -2
- package/dist/lib/types/component/display/Glyph.d.ts +2 -1
- package/dist/lib/types/component/display/Header.d.ts +1 -1
- package/dist/lib/types/component/display/IconLabel.d.ts +1 -1
- package/dist/lib/types/component/display/IconText.d.ts +1 -1
- package/dist/lib/types/component/display/Image.d.ts +1 -1
- package/dist/lib/types/component/display/Video.d.ts +1 -1
- package/dist/lib/types/component/display/WebGLCanvas.d.ts +8 -2
- package/dist/lib/types/component/editor/CodeEditor.d.ts +1 -1
- package/dist/lib/types/component/input/AbstractPickerField.d.ts +1 -1
- package/dist/lib/types/component/input/AutoCompleteDropdown.d.ts +1 -1
- package/dist/lib/types/component/input/Link.d.ts +1 -1
- package/dist/lib/types/component/input/NumberSpinner.d.ts +1 -1
- package/dist/lib/types/component/input/PasswordField.d.ts +1 -1
- package/dist/lib/types/component/input/SpinButton.d.ts +1 -1
- package/dist/lib/types/component/input/TextArea.d.ts +1 -1
- package/dist/lib/types/component/input/TextField.d.ts +3 -1
- package/dist/lib/types/component/input/UsernameField.d.ts +1 -1
- package/dist/lib/types/component/list/AbstractMarkerList.d.ts +9 -1
- package/dist/lib/types/component/list/BulletedList.d.ts +1 -0
- package/dist/lib/types/component/list/ListItem.d.ts +10 -4
- package/dist/lib/types/component/list/NumberedList.d.ts +1 -0
- package/dist/lib/types/component/menubar/MenuBarButton.d.ts +1 -1
- package/dist/lib/types/component/menubar/ToolBar.d.ts +1 -1
- package/dist/lib/types/component/menubar/ToolBarSeparator.d.ts +1 -1
- package/dist/lib/types/component/shared/VirtualRowView.d.ts +13 -1
- package/dist/lib/types/component/table/Body.d.ts +15 -2
- package/dist/lib/types/component/table/CellGeometry.d.ts +6 -0
- package/dist/lib/types/component/table/Column.d.ts +4 -0
- package/dist/lib/types/component/table/ColumnConfig.d.ts +3 -0
- package/dist/lib/types/component/table/Header.d.ts +24 -2
- package/dist/lib/types/component/table/Row.d.ts +13 -2
- package/dist/lib/types/component/table/Table.d.ts +25 -4
- package/dist/lib/types/component/table/TableExporter.d.ts +1 -1
- package/dist/lib/types/component/table/TablePanel.d.ts +2 -1
- package/dist/lib/types/component/table/cell/Cell.d.ts +1 -1
- package/dist/lib/types/component/table/cell/Header.d.ts +3 -0
- package/dist/lib/types/component/table/index.d.ts +1 -1
- package/dist/lib/types/component/tree/Tree.d.ts +1 -0
- package/dist/lib/types/core/Aria.d.ts +1 -1
- package/dist/lib/types/core/Body.d.ts +8 -2
- package/dist/lib/types/core/Component.d.ts +6 -0
- package/dist/lib/types/core/DOM.d.ts +4 -0
- package/dist/lib/types/core/DragChain.d.ts +3 -0
- package/dist/lib/types/core/Favicon.d.ts +7 -0
- package/dist/lib/types/core/FirstLayoutGate.d.ts +5 -0
- package/dist/lib/types/core/Theme.d.ts +1 -0
- package/dist/lib/types/core/Util.d.ts +1 -0
- package/dist/lib/types/core/index.d.ts +2 -0
- package/dist/lib/types/layout/Accordion.d.ts +0 -1
- package/dist/lib/types/layout/FlowLayout.d.ts +4 -0
- package/dist/lib/types/layout/HFlow.d.ts +3 -0
- package/dist/lib/types/layout/VFlow.d.ts +1 -0
- package/dist/lib/types/overlay/AbstractWindow.d.ts +1 -1
- package/dist/lib/types/overlay/Dock.d.ts +1 -0
- package/dist/lib/types/overlay/DropZoneOverlay.d.ts +1 -0
- package/dist/lib/types/overlay/Popover.d.ts +1 -1
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +1 -0
- package/package.json +2 -2
- package/dist/lib/Border-Dq6dXkmS.js +0 -2
- package/dist/lib/Border-Dq6dXkmS.js.map +0 -1
- package/dist/lib/Button-B36rBMKC.js +0 -2
- package/dist/lib/ComboBox-BjAhXXkY.js +0 -2
- package/dist/lib/ComboBox-BjAhXXkY.js.map +0 -1
- package/dist/lib/Component-CHTzJxEf.js +0 -2
- package/dist/lib/Component-CHTzJxEf.js.map +0 -1
- package/dist/lib/Container-xUbHk6l_.js +0 -2
- package/dist/lib/DOM-BeR95tE8.js.map +0 -1
- package/dist/lib/DragManager-T5Oljd0F.js +0 -2
- package/dist/lib/DragManager-T5Oljd0F.js.map +0 -1
- package/dist/lib/Glyph-CnNslL95.js +0 -2
- package/dist/lib/Glyph-CnNslL95.js.map +0 -1
- package/dist/lib/GridConstraints-D_kbd-h2.js +0 -2
- package/dist/lib/GridConstraints-D_kbd-h2.js.map +0 -1
- package/dist/lib/HBox-Dm3xgsDE.js +0 -2
- package/dist/lib/HBox-Dm3xgsDE.js.map +0 -1
- package/dist/lib/Header-CqFc2OUx.js +0 -2
- package/dist/lib/Header-CqFc2OUx.js.map +0 -1
- package/dist/lib/IconText-CTM2r0Tv.js +0 -2
- package/dist/lib/IconText-CTM2r0Tv.js.map +0 -1
- package/dist/lib/LayoutSizes-CvMmMgHJ.js +0 -2
- package/dist/lib/LayoutSizes-CvMmMgHJ.js.map +0 -1
- package/dist/lib/List-DHeOPAK2.js +0 -2
- package/dist/lib/List-DHeOPAK2.js.map +0 -1
- package/dist/lib/Menu-B6ippw-p.js +0 -2
- package/dist/lib/Menu-B6ippw-p.js.map +0 -1
- package/dist/lib/Position-DRSlWn4Z.js +0 -2
- package/dist/lib/Position-DRSlWn4Z.js.map +0 -1
- package/dist/lib/Scrollbar-CiVV3axj.js +0 -2
- package/dist/lib/Scrollbar-CiVV3axj.js.map +0 -1
- package/dist/lib/Slider-_JVvuQ8M.js +0 -2
- package/dist/lib/Slider-_JVvuQ8M.js.map +0 -1
- package/dist/lib/TabButton-DEypdlZf.js +0 -2
- package/dist/lib/TabButton-DEypdlZf.js.map +0 -1
- package/dist/lib/Tooltip-BUy6uFKN.js +0 -3
- package/dist/lib/VBox-Dr7Ge9M6.js +0 -2
- package/dist/lib/VBox-Dr7Ge9M6.js.map +0 -1
- package/dist/lib/VirtualScroller-BPy6KmSX.js +0 -2
- package/dist/lib/VirtualScroller-BPy6KmSX.js.map +0 -1
- package/dist/lib/selectionsEqual-2PJrcimg.js +0 -2
- package/dist/lib/selectionsEqual-2PJrcimg.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Position-DRSlWn4Z.js","names":[],"sources":["../../src/typescript/lib/core/Util.ts","../../src/typescript/lib/core/BaseObject.ts","../../src/typescript/lib/primitive/Size.ts","../../src/typescript/lib/primitive/Border.ts","../../src/typescript/lib/primitive/Insets.ts","../../src/typescript/lib/primitive/Position.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Size } from \"~/primitive/Size.js\";\nimport type { Insets } from \"~/primitive/Insets.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Font options for off-screen text measurement.\n * All properties default to the active theme variables when omitted.\n */\nexport interface TextMeasureOptions {\n fontFamily?: string;\n fontSize? : string;\n fontWeight?: string;\n fontStyle? : string;\n fontVariant?: string;\n fontStretch?: string;\n lineHeight?: string\n /**\n * When set, the probe wraps at this pixel width (using `pre-wrap`) instead of\n * measuring on a single `nowrap` line. The returned `height` then reflects the\n * wrapped, multi-line box. Omit to measure the natural single-line size.\n */\n maxWidth?: number;\n}\n\n/**\n * Result of an off-screen text measurement that also reports the typographic baseline.\n *\n * @remarks `baseline` is the offset from the top of the measured box to the font baseline,\n * in pixels — analogous to CSS `vertical-align: baseline` on an inline-block element.\n */\nexport interface TextMetrics {\n width: number;\n height: number;\n baseline: number;\n}\n\n/**\n * General-purpose utility functions for DOM interaction and browser environment queries.\n *\n * @category Util\n */\nexport namespace Util {\n\n // Cached text-metric results, invalidated together on theme change via\n // `invalidateTextMetricsCache`. `-1` is the \"not yet measured\" sentinel\n // (a real padding / font size / baseline / offset is always >= 0).\n let linePaddingCache: number = -1;\n let rootFontSizeCache: number = -1;\n let textBaselineCache: number = -1;\n let opticalOffsetCache: number = -1;\n\n // Generation counter bumped by `invalidateTextMetricsCache`, so a caller\n // (e.g. `Text.needsMeasure`) can tell whether its last measurement\n // predates the active theme without holding its own subscription.\n let metricsGeneration = 0;\n\n // Resolved bound-font-size results, keyed by `cssVar + \"|\" + cssRule`, so\n // every `Text` bound to the same CSS var/rule pair shares one resolution\n // per theme change instead of each instance re-probing the cascade.\n const boundFontSizeCache = new Map<string, number | null>();\n\n /**\n * Measures the rendered size of a text string using an off-screen probe `<span>`.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured `{width, height}` in pixels, ceiled to whole pixels.\n */\n export function measureTextSize(text: string, options: TextMeasureOptions = {}): Size {\n const metrics = DOM.source.measureText(text, options);\n\n return { width: metrics.width, height: metrics.height };\n }\n\n /**\n * Returns the rendered pixel width of a text string.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured width in pixels, ceiled to a whole pixel.\n */\n export function measureTextWidth(text: string, options?: TextMeasureOptions): number {\n return measureTextSize(text, options).width;\n }\n\n /**\n * Returns the active theme's leading (`--ts-ui-line-padding`) in pixels.\n *\n * @returns The integer-pixel value of `--ts-ui-line-padding`, or `4` as a\n * fallback when the variable is missing or unparseable.\n */\n function linePaddingPx(): number {\n if (linePaddingCache >= 0) {\n return linePaddingCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-line-padding\");\n const parsed = parseFloat(raw);\n\n // 2 mirrors the `--ts-ui-line-padding` default shipped by every theme\n // (see ModernTheme/DarkTheme/ClassicTheme `font.linePadding: '2px'`);\n // it only applies when the var is absent (e.g. pre-theme-apply probe).\n linePaddingCache = isNaN(parsed) ? 2 : parsed;\n\n return linePaddingCache;\n }\n\n /**\n * Returns the document root font size (`--ts-ui-font-size`) in pixels, the\n * default font size for a control that doesn't override it.\n *\n * @returns The integer-pixel root font size, or `14` as a fallback.\n */\n function rootFontSizePx(): number {\n if (rootFontSizeCache >= 0) {\n return rootFontSizeCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-font-size\");\n const parsed = parseFloat(raw);\n\n rootFontSizeCache = isNaN(parsed) ? 14 : parsed;\n\n return rootFontSizeCache;\n }\n\n /**\n * Returns a vertical text metric in integer pixels: a control's font size,\n * plus the theme leading (`--ts-ui-line-padding`) by default.\n *\n * @param options - Measurement options.\n * @param options.fontSizePx - The control's font size in pixels. Omit to use\n * the document root font size (`--ts-ui-font-size`), which is what the\n * native `<input>`-backed controls render at.\n * @param options.linePadding - Controls the leading added to the font size:\n * `true` (the default) adds the theme `--ts-ui-line-padding`, giving the\n * full rendered line box (matching the `calc(1em + …)` line-height controls\n * render at); `false` adds nothing, returning the bare font size to size a\n * box from its font without leading; a number adds that exact pixel padding.\n * @returns `round(fontSize + leading)`, where leading is the theme padding,\n * `0`, or the given number.\n *\n * @remarks With the default leading the line box scales with font size, so\n * 12px and 14px text get proportionate line boxes from the one token. Text\n * components, table rows, and the baseline computation use the default so\n * their measurement matches the rendered line box; the native input box\n * heights pass `false` so the box hugs the font size plus their own chrome.\n * The padding and root font size are cached; call\n * {@link invalidateTextMetricsCache} after a theme change to force a\n * re-read.\n */\n export function lineHeightPx(options: { fontSizePx?: number, linePadding?: boolean | number } = {}): number {\n let fs = options.fontSizePx ?? rootFontSizePx();\n\n const linePadding = options.linePadding ?? true;\n\n if (linePadding === true) {\n fs += linePaddingPx();\n } else if (typeof linePadding === \"number\") {\n fs += linePadding;\n }\n\n return Math.round(fs);\n }\n\n /**\n * Returns the content-relative text baseline for the unified line-height\n * model: the offset from the top of the `lineHeightPx()` line box to the\n * font baseline.\n *\n * @returns The baseline offset in pixels, rounded to the nearest integer.\n *\n * @remarks Computed from the canvas 2D `measureText` font metrics rather\n * than a DOM probe, so it is deterministic and UA-independent. A CSS line\n * box centres the font's ascent+descent within `line-height`; this\n * reproduces that centring with the known px line box —\n * `round(lineGap / 2 + ascent)` where `lineGap = lineHeightPx - (ascent +\n * descent)` — so the measured baseline matches where the browser paints the\n * glyph in both a native `<input>` and a `Text`/`Label`. `fontBoundingBox*`\n * (font-intrinsic, string-independent) is used in preference to\n * `actualBoundingBox*` (glyph-ink specific) so the baseline does not shift\n * per measured string; `\"X\"` is passed only to satisfy `measureText`. The\n * result is cached; call {@link invalidateTextMetricsCache} after a theme\n * change to force re-measurement.\n */\n export function measureTextBaseline(): number {\n if (textBaselineCache >= 0) {\n return textBaselineCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const gap = lineHeightPx() - (m.ascent + m.descent);\n\n textBaselineCache = Math.round(gap / 2 + m.ascent);\n\n return textBaselineCache;\n }\n\n /**\n * Returns the pixel height of a single-line input box: the theme line-box\n * height ({@link lineHeightPx}) plus the component's own vertical chrome\n * (insets + optional padding + border).\n *\n * @param insets - The component's layout insets (top/bottom read).\n * @param padding - The component's CSS padding, or `null` when it has none.\n * @param border - The component's border widths (top/bottom read).\n * @returns The single-line box height in pixels.\n *\n * @remarks Factors out the `chrome = insets + padding + border; h =\n * lineHeightPx() + chrome` idiom shared by every single-line native-input\n * box height (`TextField` / `PasswordField` / `ComboBox` / the picker fields\n * / `NumberSpinner`). Only the vertical (top/bottom) edges contribute; the\n * horizontal edges are the caller's width concern. `NumberSpinner` uniquely\n * passes its *inner input's* padding rather than its own.\n */\n export function singleLineBoxHeight(\n insets: Insets,\n padding: Insets | null,\n border: { top: number; bottom: number },\n ): number {\n const chrome = insets.getTop() + insets.getBottom()\n + (padding ? padding.getTop() + padding.getBottom() : 0)\n + border.top + border.bottom;\n\n return lineHeightPx() + chrome;\n }\n\n /**\n * Returns the downward pixel offset that moves a single line of text from\n * its line-box (geometric) centre to its optical (cap-height) centre.\n *\n * @returns The downward offset in pixels (`>= 0`), rounded to the nearest\n * integer.\n *\n * @remarks A label's visible glyphs occupy cap-top→baseline; the descender\n * band below the baseline is empty ink, so the ink's visual centre sits\n * above the font box's geometric centre and a geometrically-centred label\n * reads as too high. This returns roughly half the unused descender space —\n * `round(boxMid - inkMid)` where `boxMid = (ascent - descent) / 2` and\n * `inkMid = capTop / 2` with `capTop = actualBoundingBoxAscent` (the cap-top\n * ink of `\"X\"`) — so a consumer ([`Button`](/api/component/button/classes/Button))\n * can nudge single-line text down onto its true optical centre. Derived\n * from the same cached canvas\n * metrics as {@link measureTextBaseline}; cached and invalidated together\n * via {@link invalidateTextMetricsCache}.\n */\n export function opticalCenterOffset(): number {\n if (opticalOffsetCache >= 0) {\n return opticalOffsetCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const boxMid = (m.ascent - m.descent) / 2;\n const inkMid = m.capTop / 2;\n\n opticalOffsetCache = Math.max(0, Math.round(boxMid - inkMid));\n\n return opticalOffsetCache;\n }\n\n /**\n * Returns the generation counter for the cached text metrics, bumped once\n * every time {@link invalidateTextMetricsCache} runs.\n *\n * @returns The current generation number.\n *\n * @remarks Lets a caller that measured against a past generation (stashed\n * from a prior read of this function) tell, cheaply and without holding\n * its own theme subscription, whether a re-measure is due — the pattern\n * `Text` uses instead of subscribing to `ThemeManager` per instance.\n */\n export function textMetricsGeneration(): number {\n return metricsGeneration;\n }\n\n /**\n * Resolves a CSS custom property bound to a control's font size to a\n * pixel number, caching the result per `cssVar`/`cssRule` pair so every\n * control bound to the same token shares one resolution per theme change.\n *\n * @param cssVar - The CSS custom property name (e.g. `\"--ts-ui-font-size\"`).\n * @param cssRule - The CSS value the control's `font-size` rule is set to\n * (e.g. `\"var(--ts-ui-font-size, 14px)\"`), used as the fallback probe\n * when `cssVar`'s raw value isn't a bare, parseable pixel number (a\n * `calc(...)`-valued relative token). Pass `null` when the control has\n * no rule text of its own; the probe then falls back to `var(${cssVar})`.\n * @returns The resolved pixel size.\n *\n * @remarks Mirrors the theme-var-then-probe strategy every other cached\n * metric in this namespace uses: a simple var parses straight off its raw\n * string; a `calc(...)`-valued token falls back to\n * {@link DOMSource.resolveFontSizePx}, a cascade-evaluating probe. Cleared\n * together with the rest of the text metrics by\n * {@link invalidateTextMetricsCache}.\n */\n export function boundFontSizePx(cssVar: string, cssRule: string | null): number | null {\n const key = cssVar + \"|\" + (cssRule ?? \"\");\n const cached = boundFontSizeCache.get(key);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const raw = parseFloat(DOM.source.getThemeVar(cssVar));\n const resolved = isNaN(raw)\n ? DOM.source.resolveFontSizePx(cssRule ?? `var(${cssVar})`)\n : raw;\n\n boundFontSizeCache.set(key, resolved);\n\n return resolved;\n }\n\n /**\n * Discards every cached text metric (line box, baseline, optical offset,\n * bound font sizes) so the next read re-measures against the active theme\n * font.\n *\n * @remarks Call this whenever the active theme's font size, family, or\n * line-height changes, since the cached values reflect the font in use at\n * the time of the first measurement and would otherwise mis-align controls\n * against each other after a theme swap.\n */\n export function invalidateTextMetricsCache(): void {\n linePaddingCache = -1;\n rootFontSizeCache = -1;\n textBaselineCache = -1;\n opticalOffsetCache = -1;\n boundFontSizeCache.clear();\n metricsGeneration++;\n }\n\n /**\n * Generates a UUID string, ensuring the first character is never a digit.\n *\n * @returns A UUID v4 string with a guaranteed non-numeric first character.\n *\n * @remarks If the standard UUID generation produces a leading digit, it is replaced\n * with the letter \"a\" so the result is safe to use as a DOM id or CSS identifier.\n */\n export function generateUUID() {\n let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n let r = Math.random() * 16 | 0,\n v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n\n let first = parseInt(uuid[0]);\n if (Util.isInteger(first)) {\n uuid = \"a\" + uuid.substring(1, uuid.length);\n }\n\n return uuid;\n }\n\n /**\n * Returns true if value is an integer.\n *\n * @param value - The value to test.\n *\n * @returns `true` if `value` is an integer, `false` otherwise.\n */\n export function isInteger(value: Object) {\n return Number.isInteger(value);\n }\n\n /**\n * Clamps a number into an inclusive `[min, max]` range.\n *\n * @param value - The number to clamp.\n * @param min - The lower bound.\n * @param max - The upper bound.\n *\n * @returns `value` when it lies within the range, otherwise the nearer bound.\n *\n * @remarks Assumes `min <= max` (the framework's `min <= preferred <= max`\n * size invariant). When `min > max` the maximum wins (`clamp(v, 10, 0) === 0`)\n * — the low-first `Math.min(Math.max(...))` tie-break; callers must not rely\n * on it. `NaN` propagates (a `NaN` input returns `NaN`), matching the inlined\n * `Math.min`/`Math.max` expressions this replaces.\n */\n export function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n }\n\n /**\n * Converts a hyphen-separated identifier (e.g. `\"border-top-width\"`) to its\n * camelCase equivalent (`\"borderTopWidth\"`). Useful for translating\n * CSS-style kebab-case property names into the camelCase form expected by\n * `CSSStyleDeclaration` bracket-indexed assignment.\n *\n * @param value - The kebab-case input string.\n * @returns The camelCase equivalent.\n */\n export function kebabToCamel(value: string): string {\n return value.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n }\n\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Util } from \"~/core/Util.js\"\n\n/**\n * Base class for all library objects.\n * Automatically assigns a unique identifier on construction.\n *\n * @category Core\n */\nexport class BaseObject {\n\n private _id: string;\n\n constructor() {\n this._id = Util.generateUUID();\n }\n\n /**\n * Returns the unique identifier for this object.\n *\n * @returns The UUID string assigned at construction time.\n */\n getId() {\n return this._id;\n }\n\n /**\n * Sets the unique identifier for this object.\n *\n * @param id - The new identifier string to assign.\n */\n setId(id: string) : this {\n this._id = id;\n\n return this;\n }\n\n /**\n * Returns the runtime class name of this object.\n *\n * @returns The name of the constructor function as a string.\n */\n getClassName() {\n return this.constructor.name;\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * Represents a two-dimensional size with width and height in pixels.\n *\n * @category Util\n */\nexport interface Size {\n width: number,\n height: number\n}\n\n/**\n * The sentinel extent meaning \"no upper bound\" on a size axis.\n *\n * @category Util\n */\nexport const UNBOUNDED: number = Number.MAX_SAFE_INTEGER;\n\n/**\n * True when an extent is at or above the unbounded sentinel (recognises the\n * legacy `Number.MAX_VALUE` too).\n *\n * @param n - The extent to test.\n * @returns `true` when `n` is at or above {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function isUnbounded(n: number): boolean {\n return n >= Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Caps an extent at the unbounded sentinel so an unbounded sum cannot overflow\n * it.\n *\n * @param n - The extent to cap.\n * @returns `n`, capped at {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function saturate(n: number): number {\n return Math.min(n, UNBOUNDED);\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * A border specification built from complete CSS border strings.\n * `border` is the all-sides fallback; each per-side field overrides it for\n * that side. An unspecified side falls back to `border`, then to `\"none\"`.\n *\n * @category Util\n */\nexport interface BorderOptions {\n /** CSS `border` shorthand applied to all four sides (e.g. `\"1px solid rgb(...)\"`, `\"none\"`, `\"var(--x)\"`). */\n border?: string;\n /** CSS `border-top` value; overrides `border` for the top side. */\n borderTop?: string;\n /** CSS `border-right` value; overrides `border` for the right side. */\n borderRight?: string;\n /** CSS `border-bottom` value; overrides `border` for the bottom side. */\n borderBottom?: string;\n /** CSS `border-left` value; overrides `border` for the left side. */\n borderLeft?: string;\n}\n\n/**\n * Expands a {@link BorderOptions} into the four camelCase longhand style keys\n * (`borderTop`/`borderRight`/`borderBottom`/`borderLeft`) that `StyleRule.setMany`\n * consumes. Each side resolves via `side ?? border ?? \"none\"`, so a pure-longhand\n * map replays deterministically regardless of what else touched the rule.\n *\n * @param border - The border specification to expand.\n *\n * @returns A map of the four longhand keys to their resolved CSS values.\n *\n * @category Util\n */\nexport function borderToStyle(border: BorderOptions): Record<string, string | null> {\n const all = border.border ?? \"none\";\n\n return {\n borderTop: border.borderTop ?? all,\n borderRight: border.borderRight ?? all,\n borderBottom: border.borderBottom ?? all,\n borderLeft: border.borderLeft ?? all,\n };\n}\n\n/**\n * Best-effort leading-`<n>px` width of one side's CSS value. Returns `0` for\n * `undefined`, `none`, `0`, `var(...)`, or any non-`px` leading token. Used both\n * to parse the always-`<n>px` values `getComputedStyle` returns (authoritative,\n * post-render) and to estimate a width from a spec string before an element exists.\n *\n * @param value - A single side's CSS border value, or `undefined`.\n *\n * @returns The leading pixel width, or `0` when none can be parsed.\n *\n * @category Util\n */\nexport function borderSideWidth(value: string | undefined): number {\n if (!value) {\n return 0;\n }\n\n const match = value.trim().match(/^([\\d.]+)px\\b/i);\n\n return match ? parseFloat(match[1]) : 0;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from \"~/core/BaseObject.js\";\n\n/**\n * Represents the four directional inset (padding/margin) values for a rectangular area.\n * All values are expressed in pixels.\n *\n * @example\n * ```typescript\n * import { Insets } from '@jimka/typescript-ui/primitive';\n*\n * component.setInsets(new Insets(8, 12, 8, 12)); // top, right, bottom, left\n * ```\n *\n * @category Util\n */\nexport class Insets extends BaseObject {\n\n private _top: number;\n private _right: number;\n private _bottom: number;\n private _left: number;\n\n /**\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n constructor(top: number, right: number, bottom: number, left: number) {\n super();\n\n this._top = top || 0;\n this._right = right || 0;\n this._bottom = bottom || 0;\n this._left = left || 0;\n }\n\n /**\n * Returns the top inset in pixels.\n *\n * @returns The top inset value, defaulting to `0` if unset.\n */\n getTop() {\n return this._top || 0;\n }\n\n /**\n * Sets the top inset in pixels.\n *\n * @param value - The new top inset value in pixels.\n */\n setTop(value: number) : this {\n this._top = value;\n\n return this;\n }\n\n /**\n * Returns the right inset in pixels.\n *\n * @returns The right inset value, defaulting to `0` if unset.\n */\n getRight() {\n return this._right || 0;\n }\n\n /**\n * Sets the right inset in pixels.\n *\n * @param value - The new right inset value in pixels.\n */\n setRight(value: number) : this {\n this._right = value;\n\n return this;\n }\n\n /**\n * Returns the bottom inset in pixels.\n *\n * @returns The bottom inset value, defaulting to `0` if unset.\n */\n getBottom() {\n return this._bottom || 0;\n }\n\n /**\n * Sets the bottom inset in pixels.\n *\n * @param value - The new bottom inset value in pixels.\n */\n setBottom(value: number) : this {\n this._bottom = value;\n\n return this;\n }\n\n /**\n * Returns the left inset in pixels.\n *\n * @returns The left inset value, defaulting to `0` if unset.\n */\n getLeft() {\n return this._left || 0;\n }\n\n /**\n * Sets the left inset in pixels.\n *\n * @param value - The new left inset value in pixels.\n */\n setLeft(value: number) : this {\n this._left = value;\n\n return this;\n }\n\n /**\n * Sets all four inset values at once.\n *\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n set(top: number, right: number, bottom: number, left: number) : this {\n this._top = top;\n this._right = right;\n this._bottom = bottom;\n this._left = left;\n\n return this;\n }\n\n /**\n * Returns the insets as a CSS shorthand string (e.g. `\"4px 4px 4px 4px\"`).\n *\n * @returns A CSS margin/padding shorthand string with all four sides in top-right-bottom-left order.\n */\n render() {\n return this.getTop() + \"px \" + this.getRight() + \"px \" + this.getBottom() + \"px \" + this.getLeft() + \"px\";\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * CSS `position` values used by the framework.\n *\n * The framework positions every component absolutely (see\n * [ARCHITECTURE.md](/ARCHITECTURE.md) §Positioning). Only three values\n * are exposed:\n *\n * - `ABSOLUTE` — the universal default for every framework component.\n * - `FIXED` — the documented exception for floating overlays that anchor to\n * the viewport (`AnimatedDropdown`, `Popover`, `Notification`, `Dialog`,\n * `DialogBackdrop`). Set internally by these subclasses; never by callers.\n * - `STATIC` — the documented exception for an HTML element whose native\n * semantics require in-flow rendering (currently only `Legend`, which needs\n * the notch in its parent `<fieldset>`'s border).\n *\n * Other CSS values (`relative`, `sticky`, `initial`, `inherit`) are\n * intentionally **not** members. Application code does not call\n * `setPosition` — that setter is `protected` on `Component`.\n *\n * @category Util\n */\nexport enum Position {\n STATIC = \"static\",\n FIXED = \"fixed\",\n ABSOLUTE = \"absolute\",\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./DOM-BeR95tE8.js";import{_ as t,m as n,t as r,x as i}from"./Component-CHTzJxEf.js";import{t as a}from"./ListenerBag-WPdKuuds.js";import{t as o}from"./Glyph-CnNslL95.js";var AutoRepeat=class{_initialDelay;_decay;_floor;_onTick;_handle=null;_delay;constructor(e){this._initialDelay=e.initialDelay,this._decay=e.decay,this._floor=e.floor,this._onTick=e.onTick,this._delay=e.initialDelay}start(){this._onTick(),this._delay=this._initialDelay,this.scheduleNext()}stop(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null),this._delay=this._initialDelay}isRunning(){return this._handle!==null}scheduleNext(){this._handle=setTimeout(()=>{this._onTick(),this._delay=Math.max(this._floor,this._delay*this._decay),this.scheduleNext()},this._delay)}};function scrollShadowRamp(e){return Math.max(0,Math.min(1,(e-1)/40))}function scrollShadowBoxShadow(){let e=`12px`;return`inset 0 ${e} ${e} -${e} var(--ts-ss-top, transparent),inset 0 -${e} ${e} -${e} var(--ts-ss-bottom, transparent),inset ${e} 0 ${e} -${e} var(--ts-ss-left, transparent),inset -${e} 0 ${e} -${e} var(--ts-ss-right, transparent)`}function scrollShadowEdgeValue(e){return e===0?null:`color-mix(in srgb, var(--ts-ui-scroll-shadow-color) ${e}%, transparent)`}var s=12,c=2,l=30,u=10,d=400,f=.75,p=40,m=40,ScrollArrowButton=class extends r{_glyph;_disabled=!1;_listeners=new a;_repeat;constructor(e){super(),this.setWidth(s),this.setHeight(s),this.setCursor(`default`),this.setBackgroundColor(`var(--ts-ui-scrollbar-arrow-bg, transparent)`),this.setForegroundColor(`var(--ts-ui-scrollbar-arrow-color, rgba(0, 0, 0, 0.55))`),t.isReducedMotion()||this.setTransition(`color 120ms ease-out`),this._glyph=new o(`unicode-arrow-`+e),this._glyph.setPreferredSize({width:s,height:s}),this._glyph.setFontSize(u),this._glyph.setPointerEvents(`none`),super.addComponent(this._glyph),this._repeat=new AutoRepeat({initialDelay:d,decay:f,floor:p,onTick:()=>this.emit(`tick`)}),i.addListener(this,`mousedown`,this._onMouseDown),i.addListener(this,`mouseover`,this._onMouseOver),i.addListener(this,`mouseout`,this._onMouseOut),i.addViewportListener(this,`mouseup`,this._onMouseUp),i.addViewportListener(this,`mouseleave`,this._onMouseUp)}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}isDisabledState(){return this._disabled}setDisabledState(e){this._disabled!==e&&(this._disabled=e,e?(this._repeat.stop(),this.setForegroundColor(`var(--ts-ui-scrollbar-arrow-disabled-color, rgba(0, 0, 0, 0.18))`)):this.setForegroundColor(`var(--ts-ui-scrollbar-arrow-color, rgba(0, 0, 0, 0.55))`))}_onMouseDown=e=>(this._disabled||this._repeat.start(),{stop:!0,prevent:!0});_onMouseUp=()=>{this._repeat.isRunning()&&this._repeat.stop()};_onMouseOver=()=>{this._disabled||this.setBackgroundColor(`var(--ts-ui-scrollbar-arrow-hover-bg, rgba(0, 0, 0, 0.06))`)};_onMouseOut=()=>{this.setBackgroundColor(`var(--ts-ui-scrollbar-arrow-bg, transparent)`)}},Scrollbar=class extends r{_orientation=`vertical`;_thumb;_viewportSize=0;_contentSize=0;_scrollPosition=0;_thumbSize=-1;_thumbPos=-1;_dragStartClient=0;_dragStartScroll=0;_listeners=new a;_arrowsEnabled=!0;_arrowStep=m;_arrowStart=null;_arrowEnd=null;constructor(e=`vertical`,t){super(t),this._orientation=e,t?.arrowStep!==void 0&&(this._arrowStep=t.arrowStep),t?.arrowsEnabled!==void 0&&(this._arrowsEnabled=t.arrowsEnabled),this.setBackgroundColor(`var(--ts-ui-scrollbar-track, rgba(0, 0, 0, 0.04))`),this.setUserSelect(`none`),this.getAria().setHidden(!0),this.isVertical()?this.setWidth(s):this.setHeight(s),this._thumb=new r,this._thumb.setBackgroundColor(`var(--ts-ui-scrollbar-thumb, rgba(0, 0, 0, 0.35))`),this._thumb.setCursor(`default`),this.isVertical()?(this._thumb.setX(c),this._thumb.setY(0),this._thumb.setWidth(s-2*c)):(this._thumb.setX(0),this._thumb.setY(c),this._thumb.setHeight(s-2*c)),super.addComponent(this._thumb),this._arrowsEnabled&&this.buildArrows(),i.addListener(this._thumb,`mousedown`,this._onDragStart),i.addListener(this._thumb,`touchstart`,this._onDragStart),i.addListener(this._thumb,`mouseover`,this._onThumbMouseOver),i.addListener(this._thumb,`mouseout`,this._onThumbMouseOut),i.addListener(this,`mousedown`,this._onTrackClick),i.addListener(this,`touchstart`,this._onTrackClick),this.applyListeners(t?.listeners)}buildArrows(){let e=this.isVertical()?`up`:`left`,t=this.isVertical()?`down`:`right`;this._arrowStart=new ScrollArrowButton(e),this._arrowStart.setX(0),this._arrowStart.setY(0),this._arrowStart.on(`tick`,this._onArrowStartTick),this._arrowStart.setDisabledState(!0),super.addComponent(this._arrowStart),this._arrowEnd=new ScrollArrowButton(t),this._arrowEnd.setX(0),this._arrowEnd.setY(0),this._arrowEnd.on(`tick`,this._onArrowEndTick),super.addComponent(this._arrowEnd)}_onArrowStartTick=()=>this.onArrowTick(-1);_onArrowEndTick=()=>this.onArrowTick(1);onArrowTick(e){let t=Math.max(0,this._contentSize-this._viewportSize),n=Math.max(0,Math.min(t,this._scrollPosition+e*this._arrowStep));n!==this._scrollPosition&&this.emit(`scroll`,n)}disposeArrows(){this._arrowStart&&=(super.removeComponent(this._arrowStart),null),this._arrowEnd&&=(super.removeComponent(this._arrowEnd),null)}_onThumbMouseOver=()=>{this._thumb.setBackgroundColor(`var(--ts-ui-scrollbar-thumb-hover, rgba(0, 0, 0, 0.55))`)};_onThumbMouseOut=()=>{this._thumb.setBackgroundColor(`var(--ts-ui-scrollbar-thumb, rgba(0, 0, 0, 0.35))`)};init(e){return super.init(e),this.setTouchAction(`none`),this}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}setMetrics(e,t,n){this._viewportSize=e,this._contentSize=t,this._scrollPosition=n;let r=t>e;if(this.setDisplayed(r),!r)return this;let i=this.getTrackLength();if(i<=0)return this;let a=e/t,o=Math.max(l,Math.floor(i*a));this._thumbSize!==o&&(this._thumbSize=o,this.setThumbSize(o));let c=Math.max(0,t-e),u=Math.max(0,i-o),d=c>0?Math.round(n/c*u):0;if(this._thumbPos!==d&&(this._thumbPos=d,this.setThumbPos(d)),this._arrowsEnabled&&this._arrowStart&&this._arrowEnd){let e=this.isVertical()?this.getHeight():this.getWidth(),t=Math.max(0,e-s);this.isVertical()?this._arrowEnd.setY(t):this._arrowEnd.setX(t),this._arrowStart.setDisabledState(n<=0),this._arrowEnd.setDisabledState(n>=c)}return this}getTrackWidth(){return s}getOrientation(){return this._orientation}isArrowsEnabled(){return this._arrowsEnabled}setArrowsEnabled(e){return this._arrowsEnabled===e?this:(this._arrowsEnabled=e,e?this.buildArrows():this.disposeArrows(),this.setMetrics(this._viewportSize,this._contentSize,this._scrollPosition),this)}getArrowStep(){return this._arrowStep}setArrowStep(e){return this._arrowStep=e,this}isVertical(){return this._orientation===`vertical`}getTrackLength(){let e=this.isVertical()?this.getHeight():this.getWidth(),t=this._arrowsEnabled?2*s:0;return Math.max(0,e-t)}getTrackOrigin(){return this._arrowsEnabled?s:0}setThumbSize(e){this.isVertical()?this._thumb.setHeight(e):this._thumb.setWidth(e)}setThumbPos(e){let t=this.getTrackOrigin();this.isVertical()?this._thumb.setY(t+e):this._thumb.setX(t+e)}extractClientPrimary(e){let t=this.isVertical(),n=e;if(n.touches!==void 0){let e=n.touches.length>0?n.touches[0]:n.changedTouches[0];return e?t?e.clientY:e.clientX:0}let r=e;return t?r.clientY:r.clientX}_onDragStart=t=>{t.preventDefault(),this._dragStartClient=this.extractClientPrimary(t),this._dragStartScroll=this._scrollPosition,i.addViewportListener(this,`mousemove`,this._onDragMove),i.addViewportListener(this,`mouseup`,this._onDragEnd),i.addViewportListener(this,`touchmove`,this._onDragMove),i.addViewportListener(this,`touchend`,this._onDragEnd),i.addViewportListener(this,`touchcancel`,this._onDragEnd),e.sink.apply(e.source.getBody(),{style:{pointerEvents:`none`}})};_onDragMove=e=>{let t=this.getTrackLength(),n=Math.max(0,this._contentSize-this._viewportSize),r=Math.max(0,t-this._thumbSize);if(r<=0)return!0;let i=(this.extractClientPrimary(e)-this._dragStartClient)/r*n,a=Math.max(0,Math.min(n,this._dragStartScroll+i));return this.emit(`scroll`,a),!0};_onDragEnd=t=>(i.removeViewportListener(this,`mousemove`,this._onDragMove),i.removeViewportListener(this,`mouseup`,this._onDragEnd),i.removeViewportListener(this,`touchmove`,this._onDragMove),i.removeViewportListener(this,`touchend`,this._onDragEnd),i.removeViewportListener(this,`touchcancel`,this._onDragEnd),e.sink.apply(e.source.getBody(),{style:{pointerEvents:``}}),!0);_onTrackClick=t=>{t.preventDefault();let n=this.isVertical(),r,i=t;if(i.touches!==void 0){let t=i.touches.length>0?i.touches[0]:i.changedTouches[0],a=this.getElement();if(!t||!a)return;let o=e.source.getViewportRect(this);r=n?t.clientY-o.top:t.clientX-o.left}else{let e=t;r=n?e.offsetY:e.offsetX}let a=this.getTrackOrigin(),o=n?this.getHeight():this.getWidth();if(this._arrowsEnabled&&(r<a||r>=o-s))return;let c=r-a<this._thumbPos+this._thumbSize/2?-1:1,l=Math.max(0,this._contentSize-this._viewportSize),u=Math.max(0,Math.min(l,this._scrollPosition+c*this._viewportSize));this.emit(`scroll`,u)}},h=n(Scrollbar);export{AutoRepeat as a,scrollShadowRamp as i,scrollShadowBoxShadow as n,scrollShadowEdgeValue as r,h as t};
|
|
2
|
-
//# sourceMappingURL=Scrollbar-CiVV3axj.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Scrollbar-CiVV3axj.js","names":[],"sources":["../../src/typescript/lib/core/AutoRepeat.ts","../../src/typescript/lib/core/ScrollShadow.ts","../../src/typescript/lib/component/container/Scrollbar.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * Construction options for {@link AutoRepeat}.\n *\n * @category Core\n */\nexport interface AutoRepeatOptions {\n /** Delay before the first repeat tick, in ms. */\n initialDelay: number;\n /** Multiplier applied to the delay after each tick (`0 < decay <= 1`). */\n decay: number;\n /** Lower bound the decaying delay never drops below, in ms. */\n floor: number;\n /** Invoked once immediately on {@link AutoRepeat.start} and once per scheduled tick. */\n onTick: () => void;\n}\n\n/**\n * The press-and-hold *accelerating* auto-repeat state machine, extracted from the\n * spin button and scrollbar arrow so both drive one implementation.\n *\n * {@link start} fires `onTick` once immediately, then schedules repeats whose\n * interval starts at `initialDelay` and shrinks by `decay` after every tick,\n * never dropping below `floor`. {@link stop} cancels the schedule and resets the\n * interval, so a subsequent press begins again at `initialDelay`.\n *\n * It is a plain class (no DOM element, so not `callable()`-wrapped) and drives an\n * owner-supplied callback rather than emitting its own events — each host keeps\n * dispatching through its own event surface. `setTimeout` is a process timer, not\n * a DOM call, so it does not route through the DOM seam.\n *\n * @category Core\n */\nexport class AutoRepeat {\n\n private readonly _initialDelay: number;\n private readonly _decay: number;\n private readonly _floor: number;\n private readonly _onTick: () => void;\n private _handle: ReturnType<typeof setTimeout> | null = null;\n private _delay: number;\n\n /**\n * @param options - The repeat timing and the per-tick callback.\n */\n constructor(options: AutoRepeatOptions) {\n this._initialDelay = options.initialDelay;\n this._decay = options.decay;\n this._floor = options.floor;\n this._onTick = options.onTick;\n this._delay = options.initialDelay;\n }\n\n /**\n * Fires `onTick` immediately, then schedules accelerating repeats starting\n * at `initialDelay`.\n */\n start(): void {\n this._onTick();\n this._delay = this._initialDelay;\n this.scheduleNext();\n }\n\n /**\n * Cancels any pending schedule and resets the interval to `initialDelay`.\n */\n stop(): void {\n if (this._handle !== null) {\n clearTimeout(this._handle);\n this._handle = null;\n }\n\n this._delay = this._initialDelay;\n }\n\n /**\n * Returns whether a repeat schedule is currently armed.\n *\n * @returns `true` between {@link start} and {@link stop}.\n */\n isRunning(): boolean {\n return this._handle !== null;\n }\n\n /**\n * Schedules the next tick at the current interval, then decays the interval\n * (×`decay`, floored at `floor`) for the tick after it.\n */\n private scheduleNext(): void {\n this._handle = setTimeout(() => {\n this._onTick();\n this._delay = Math.max(this._floor, this._delay * this._decay);\n this.scheduleNext();\n }, this._delay);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * Shared visual recipe for the position-aware scroll-edge shadows. Both scroll\n * systems paint the same fade — {@link Panel} over native `overflow` scrolling\n * and {@link VirtualScroller} over transform-based virtual lists — so the\n * geometry constants, the box-shadow recipe, and the per-edge colour ramp live\n * here as the single source of truth. Each owner keeps its own overlay element\n * and per-edge cache; only the drift-prone visual maths is shared.\n *\n * @category Core\n */\n\n/**\n * Reach in pixels of each scroll-edge shadow — used as the inset shadow's\n * offset, blur, and (negative) spread, so each edge's fade hugs its border and\n * dies out roughly this far inward.\n *\n * Fixed framework-side rather than themed, for the same reason the keyboard\n * focus indicator fixes its `2px` width (see `Theme.indicator.focus`): the\n * colour is the only part a theme needs to vary, and a constant keeps the\n * overlay's four-shadow geometry simple. `12px` reads as a soft edge cue\n * without masking a meaningful strip of content.\n */\nexport const SCROLL_SHADOW_EXTENT_PX = 12;\n\n/**\n * Distance in pixels over which an edge's shadow ramps from none to full as the\n * scroll position moves away from that edge's extreme. The strength is\n * `clamp(distanceFromExtreme / this, 0, 1)`, so the shadow fades in smoothly\n * just after leaving an edge and fades out as the opposite edge is approached,\n * instead of popping on/off at a single-pixel threshold. `40px` gives a visible\n * fade without staying faint through a meaningful amount of overflow.\n */\nexport const SCROLL_SHADOW_RAMP_PX = 40;\n\n/**\n * Ramps an edge's shadow in by how far the scroll position sits past that\n * edge's extreme. The `- 1` folds in a sub-pixel epsilon: within 1px of an\n * extreme the strength is 0, so a fractional scrollSize/clientSize mismatch\n * can't leave a phantom fade.\n *\n * @param distance - Pixels the scroll position is past the edge's extreme.\n * @returns The edge strength in the range 0–1.\n */\nexport function scrollShadowRamp(distance: number): number {\n return Math.max(0, Math.min(1, (distance - 1) / SCROLL_SHADOW_RAMP_PX));\n}\n\n/**\n * Builds the four-layer inset `box-shadow` recipe — one blurred shadow per edge,\n * each gated by a local custom property (`--ts-ss-top` / `-bottom` / `-left` /\n * `-right`) defaulting to `transparent`, so lighting an edge is a single\n * property flip rather than a shadow rebuild. The `-extent` spread keeps each\n * shadow hugging its own edge while the equal blur fades it inward over\n * `extent`px, so the edge reads as a soft cast shadow rather than the\n * hard-terminated band a `linear-gradient` would paint.\n *\n * @returns The `box-shadow` value.\n */\nexport function scrollShadowBoxShadow(): string {\n const extent = SCROLL_SHADOW_EXTENT_PX + \"px\";\n\n return (\n `inset 0 ${extent} ${extent} -${extent} var(--ts-ss-top, transparent),` +\n `inset 0 -${extent} ${extent} -${extent} var(--ts-ss-bottom, transparent),` +\n `inset ${extent} 0 ${extent} -${extent} var(--ts-ss-left, transparent),` +\n `inset -${extent} 0 ${extent} -${extent} var(--ts-ss-right, transparent)`\n );\n}\n\n/**\n * Value for one edge's shadow custom property: the theme shadow colour scaled\n * toward transparent by `percent`, or `null` at zero so the `box-shadow` layer\n * falls back to its `transparent` default.\n *\n * @param percent - The edge strength as a whole percentage (0–100).\n * @returns The `color-mix` value, or `null` when the edge is off.\n */\nexport function scrollShadowEdgeValue(percent: number): string | null {\n return percent === 0\n ? null\n : `color-mix(in srgb, var(--ts-ui-scroll-shadow-color) ${percent}%, transparent)`;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Animation } from \"~/core/Animation.js\";\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { AutoRepeat } from \"~/core/AutoRepeat.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport type { HorizontalSide } from \"~/primitive/Edge.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation } from \"~/primitive/Axis.js\";\n\n/**\n * String-literal union of the events emitted by {@link Scrollbar}.\n *\n * @category Components\n */\nexport type ScrollbarEvent = \"scroll\";\n\n/**\n * String-literal union of the events emitted by the file-local\n * `ScrollArrowButton`.\n */\ntype ScrollArrowEvent = \"tick\";\n\nconst TRACK_WIDTH = 12;\nconst THUMB_INSET = 2;\nconst THUMB_MIN_SIZE = 30;\n\n// Font size for the Unicode triangle character rendered in each arrow button.\n// The arrow box is TRACK_WIDTH (12) px square; the ambient 14 px theme font\n// produces a 16 px line-box that overflows the 12 px element and is clipped\n// at the bottom by `overflow: hidden`, leaving the visible triangle slid up\n// against the top edge. 10 px shrinks the line-box (= font-size × line-height\n// 1) below the element height so the character fits with even padding above\n// and below — matches the value [`AccordionIndicator`](./AccordionIndicator.ts)\n// uses for its `▶` chevron.\nconst ARROW_GLYPH_FONT_SIZE = 10;\n\n// Initial hold-repeat delay and acceleration parameters for ScrollArrowButton.\n// Mirrors SpinButton's scheduler so a long press on either widget produces the\n// same accelerating tick cadence — 400 ms first interval, multiplied by 0.75\n// each tick, floored at 40 ms.\nconst ARROW_REPEAT_INITIAL_MS = 400;\nconst ARROW_REPEAT_DECAY = 0.75;\nconst ARROW_REPEAT_FLOOR_MS = 40;\n\n// Default per-click scroll step in pixels for arrow buttons. Roughly two rows\n// at default font size in the Table; chosen as a fixed pixel value rather than\n// a derived fraction of viewport so the step size stays predictable as content\n// grows. Owners can override via `setArrowStep(px)`.\nconst DEFAULT_ARROW_STEP_PX = 40;\n\n// Crossfade duration for the arrow's enabled↔disabled colour swap. Matches the\n// 120 ms ease-out cadence Checkbox / Toggle / RadioButton use for their state\n// crossfades so the scrollbar's arrows read as the same UI vocabulary; short\n// enough to feel instant while softening the hard colour flip at each edge.\nconst ARROW_FADE_DURATION_MS = 120;\n\n/**\n * Callback type fired by {@link Scrollbar} when the user drags the thumb or\n * clicks the track. Receives the new scroll position in pixels.\n *\n * @category Components\n */\nexport type ScrollbarListener = (position: number) => void;\n\n/**\n * Construction-time options for {@link Scrollbar}.\n *\n * @category Components\n */\nexport interface ScrollbarOptions extends ComponentOptions {\n\n /**\n * When `true`, the scrollbar renders classic OS-style arrow buttons at\n * each end of the track (up/down for vertical, left/right for horizontal).\n * The buttons step the scroll position by {@link ScrollbarOptions.arrowStep}\n * pixels per click and accelerate while held. The matching arrow shows a\n * dimmed disabled-state colour when scroll is already at that edge.\n * Defaults to `true`; set `false` to suppress the arrows for a minimalist\n * look.\n */\n arrowsEnabled?: boolean;\n\n /**\n * Per-click scroll step in pixels for the arrow buttons. Ignored when\n * `arrowsEnabled` is `false`. Defaults to `40`.\n */\n arrowStep?: number;\n\n /**\n * Multi-event listener bag dispatched to {@link Scrollbar.on} at\n * construction time.\n */\n listeners?: {\n scroll?: ScrollbarListener;\n };\n}\n\n/**\n * Direction for a `ScrollArrowButton`. `\"up\"` / `\"down\"` go on the ends\n * of a vertical scrollbar; `\"left\"` / `\"right\"` on a horizontal one.\n */\ntype ArrowDirection = HorizontalSide | \"up\" | \"down\";\n\n/**\n * A press-and-hold arrow button rendered at one end of a {@link Scrollbar}'s\n * track when arrows are enabled. File-local — not exported from the container\n * barrel because it is a Scrollbar implementation detail.\n *\n * Mirrors the [`SpinButton`](/api/component/input/classes/SpinButton)\n * hold-repeat cadence: a click fires one tick, holding accelerates from a\n * 400 ms initial interval to a 40 ms floor, and release cancels the schedule.\n * When in the disabled state, mousedown is ignored and the glyph renders in\n * the dim colour token.\n */\nclass ScrollArrowButton extends Component {\n\n private _glyph: Glyph;\n private _disabled: boolean = false;\n private _listeners: ListenerBag<ScrollArrowEvent> = new ListenerBag<ScrollArrowEvent>();\n private _repeat: AutoRepeat;\n\n /**\n * Constructs a square TRACK_WIDTH × TRACK_WIDTH arrow button pointing in\n * the given direction.\n *\n * @param direction - One of `\"up\"`, `\"down\"`, `\"left\"`, `\"right\"`.\n */\n constructor(direction: ArrowDirection) {\n super();\n\n this.setWidth(TRACK_WIDTH);\n this.setHeight(TRACK_WIDTH);\n this.setCursor(\"default\");\n this.setBackgroundColor(\"var(--ts-ui-scrollbar-arrow-bg, transparent)\");\n this.setForegroundColor(\"var(--ts-ui-scrollbar-arrow-color, rgba(0, 0, 0, 0.55))\");\n\n // Fade the enabled↔disabled colour swap in setDisabledState instead of a hard\n // switch. Declared at construction (mirrors Checkbox's crossfade) so the initial\n // colour — the start arrow's dim state set by Scrollbar.buildArrows before first\n // paint — appears instantly, and only later at-edge toggles fade. Honours\n // prefers-reduced-motion.\n if (!Animation.isReducedMotion()) {\n this.setTransition(\"color \" + ARROW_FADE_DURATION_MS + \"ms ease-out\");\n }\n\n // Fill the full TRACK_WIDTH × TRACK_WIDTH button so `text-align: center`\n // + `line-height: 1` (Glyph char-mode defaults) centre the character\n // within that box. The explicit `fontSize` shrinks the inherited\n // 14 px size so the Unicode triangle's line-box (which scales with\n // font-size) fits inside the 12 px element box and isn't clipped at\n // the bottom by `overflow: hidden` — mirrors the same fix\n // AccordionIndicator applies to its `▶` chevron.\n this._glyph = new Glyph(\"unicode-arrow-\" + direction);\n this._glyph.setPreferredSize({ width: TRACK_WIDTH, height: TRACK_WIDTH });\n this._glyph.setFontSize(ARROW_GLYPH_FONT_SIZE);\n // The glyph fills the whole button, so without this a click's target is\n // the glyph element. The Event system routes `addListener` callbacks only\n // to the exact target id (no bubbling), so the arrow's own\n // mousedown/mouseover/mouseout handlers below would never fire. Making\n // the glyph non-interactive lets pointer events fall through to the arrow.\n this._glyph.setPointerEvents(\"none\");\n\n super.addComponent(this._glyph);\n\n this._repeat = new AutoRepeat({\n initialDelay: ARROW_REPEAT_INITIAL_MS,\n decay: ARROW_REPEAT_DECAY,\n floor: ARROW_REPEAT_FLOOR_MS,\n onTick: () => this.emit(\"tick\"),\n });\n\n Event.addListener(this, \"mousedown\", this._onMouseDown);\n Event.addListener(this, \"mouseover\", this._onMouseOver);\n Event.addListener(this, \"mouseout\", this._onMouseOut);\n Event.addViewportListener(this, \"mouseup\", this._onMouseUp);\n Event.addViewportListener(this, \"mouseleave\", this._onMouseUp);\n }\n\n /**\n * Registers a listener for one of this arrow button's events.\n *\n * @param event - `\"tick\"` fires on each logical tick (initial mousedown\n * plus every subsequent hold-repeat tick).\n * @param listener - The callback invoked when the event fires.\n *\n * @returns This arrow button, for method chaining.\n */\n on(event: \"tick\", listener: () => void): this;\n on(event: ScrollArrowEvent, 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 arrow button, for method chaining.\n */\n off(event: ScrollArrowEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with no arguments.\n *\n * @param event - The event to emit.\n */\n protected emit(event: \"tick\"): void;\n protected emit(event: ScrollArrowEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Returns whether this arrow is currently in the at-edge disabled state.\n *\n * @returns `true` when disabled, `false` otherwise.\n */\n isDisabledState(): boolean {\n return this._disabled;\n }\n\n /**\n * Toggles the disabled visual state and behaviour. Disabled arrows render\n * the glyph in the dim colour token and ignore mousedown events; any\n * in-flight hold-repeat schedule is cancelled.\n *\n * @param disabled - `true` to disable, `false` to enable.\n */\n setDisabledState(disabled: boolean): void {\n if (this._disabled === disabled) {\n return;\n }\n\n this._disabled = disabled;\n\n if (disabled) {\n this._repeat.stop();\n this.setForegroundColor(\"var(--ts-ui-scrollbar-arrow-disabled-color, rgba(0, 0, 0, 0.18))\");\n } else {\n this.setForegroundColor(\"var(--ts-ui-scrollbar-arrow-color, rgba(0, 0, 0, 0.55))\");\n }\n }\n\n /**\n * Handles mousedown on the button. Stops propagation so the parent\n * Scrollbar's track-click handler does not also fire, then (if not\n * disabled) fires the first tick and schedules accelerating repeats.\n *\n * @param _e - The mousedown event.\n * @returns `{ stop: true, prevent: true }`, consuming the press and suppressing the browser's default text selection.\n */\n private _onMouseDown = (_e: MouseEvent): Event.ListenerResult => {\n if (!this._disabled) {\n this._repeat.start();\n }\n\n return { stop: true, prevent: true };\n };\n\n /**\n * Cancels the hold-repeat schedule on mouseup or when the pointer leaves\n * the viewport.\n */\n private _onMouseUp = (): void => {\n if (!this._repeat.isRunning()) {\n return;\n }\n\n this._repeat.stop();\n };\n\n /**\n * Darkens the button background on hover, mirroring the thumb-hover idiom.\n */\n private _onMouseOver = (): void => {\n if (this._disabled) {\n return;\n }\n\n this.setBackgroundColor(\"var(--ts-ui-scrollbar-arrow-hover-bg, rgba(0, 0, 0, 0.06))\");\n };\n\n /**\n * Restores the resting background when the pointer leaves the button.\n */\n private _onMouseOut = (): void => {\n this.setBackgroundColor(\"var(--ts-ui-scrollbar-arrow-bg, transparent)\");\n };\n\n}\n\n/**\n * A custom virtual scrollbar overlay.\n *\n * Designed for components that own their own scroll state (e.g. transform-based\n * virtual lists) and don't expose native browser scrolling. The owner pushes\n * viewport/content metrics in via {@link Scrollbar.setMetrics} and subscribes\n * to scroll position changes via {@link Scrollbar.on}.\n *\n * The thumb is dragged with the mouse; clicking the track above/beside the\n * thumb pages by one viewport. The scrollbar hides itself when content fits in\n * the viewport. Classic OS-style arrow buttons at each end of the track are\n * controlled by {@link ScrollbarOptions.arrowsEnabled} — enabled by default;\n * set it `false` for a minimalist look.\n *\n * Available in vertical (default) and horizontal orientations; the owner is\n * responsible for sizing the primary axis (height for vertical, width for\n * horizontal) and positioning the bar on the cross axis.\n *\n * @category Components\n */\nclass Scrollbar extends Component<ScrollbarOptions> {\n\n private _orientation : AxisOrientation = \"vertical\";\n private _thumb : Component;\n private _viewportSize : number = 0;\n private _contentSize : number = 0;\n private _scrollPosition : number = 0;\n // Sentinel `-1` rather than `0` so the first `setMetrics` call always\n // writes the thumb's size/position through to the DOM, even when the\n // computed values happen to be `0` (e.g. scroll position at top with\n // arrows enabled, where the constructor-time `setY(0)` would otherwise\n // never get corrected to the arrow-region origin offset).\n private _thumbSize : number = -1;\n private _thumbPos : number = -1;\n private _dragStartClient : number = 0;\n private _dragStartScroll : number = 0;\n private _listeners : ListenerBag<ScrollbarEvent> = new ListenerBag<ScrollbarEvent>();\n\n private _arrowsEnabled : boolean = true;\n private _arrowStep : number = DEFAULT_ARROW_STEP_PX;\n private _arrowStart : ScrollArrowButton | null = null;\n private _arrowEnd : ScrollArrowButton | null = null;\n\n /**\n * Constructs a Scrollbar.\n *\n * @param orientation - `\"vertical\"` (default) or `\"horizontal\"`.\n * @param options - Optional configuration bag. ComponentOptions fields are\n * forwarded to `super` so the standard cascade applies; the\n * arrow-specific fields are read here ahead of any DOM construction.\n */\n constructor(orientation: AxisOrientation = \"vertical\", options?: ScrollbarOptions) {\n super(options);\n\n this._orientation = orientation;\n\n // Pull arrow configuration out of options ahead of any DOM work so the\n // thumb / arrow construction below sees the final flags. ComponentOptions\n // fields (visible, backgroundColor, etc.) are already applied by super.\n if (options?.arrowStep !== undefined) {\n this._arrowStep = options.arrowStep;\n }\n if (options?.arrowsEnabled !== undefined) {\n this._arrowsEnabled = options.arrowsEnabled;\n }\n\n this.setBackgroundColor(\"var(--ts-ui-scrollbar-track, rgba(0, 0, 0, 0.04))\");\n this.setUserSelect(\"none\");\n\n // Purely decorative: the real scroll semantics live on the native scroll\n // region this widget mirrors (overlay Panel, VirtualScroller), so hide the\n // track / thumb / arrow subtree from assistive tech rather than have it\n // announce a stack of non-interactive divs. Matches Spacer / Glyph.\n this.getAria().setHidden(true);\n\n if (this.isVertical()) {\n this.setWidth(TRACK_WIDTH);\n } else {\n this.setHeight(TRACK_WIDTH);\n }\n\n this._thumb = new Component();\n this._thumb.setBackgroundColor(\"var(--ts-ui-scrollbar-thumb, rgba(0, 0, 0, 0.35))\");\n this._thumb.setCursor(\"default\");\n\n if (this.isVertical()) {\n this._thumb.setX(THUMB_INSET);\n this._thumb.setY(0);\n this._thumb.setWidth(TRACK_WIDTH - 2 * THUMB_INSET);\n } else {\n this._thumb.setX(0);\n this._thumb.setY(THUMB_INSET);\n this._thumb.setHeight(TRACK_WIDTH - 2 * THUMB_INSET);\n }\n\n super.addComponent(this._thumb);\n\n if (this._arrowsEnabled) {\n this.buildArrows();\n }\n\n Event.addListener(this._thumb, \"mousedown\", this._onDragStart);\n Event.addListener(this._thumb, \"touchstart\", this._onDragStart);\n Event.addListener(this._thumb, \"mouseover\", this._onThumbMouseOver);\n Event.addListener(this._thumb, \"mouseout\", this._onThumbMouseOut);\n Event.addListener(this, \"mousedown\", this._onTrackClick);\n Event.addListener(this, \"touchstart\", this._onTrackClick);\n\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Constructs and wires the two arrow buttons. Start arrow sits at the\n * primary-axis origin; end arrow's primary-axis position is set lazily in\n * `setMetrics` because the cross-axis extent changes with bar size.\n * Disabled-state for the start arrow is pre-set since `_scrollPosition`\n * defaults to 0 — without this the start arrow renders enabled for one\n * frame before `setMetrics` corrects it.\n */\n private buildArrows(): void {\n const startDirection: ArrowDirection = this.isVertical() ? \"up\" : \"left\";\n const endDirection: ArrowDirection = this.isVertical() ? \"down\" : \"right\";\n\n this._arrowStart = new ScrollArrowButton(startDirection);\n this._arrowStart.setX(0);\n this._arrowStart.setY(0);\n this._arrowStart.on(\"tick\", this._onArrowStartTick);\n this._arrowStart.setDisabledState(true);\n super.addComponent(this._arrowStart);\n\n this._arrowEnd = new ScrollArrowButton(endDirection);\n // End arrow's primary-axis origin depends on the bar's outer size; we\n // position it inside `setMetrics`. Cross-axis stays at 0.\n this._arrowEnd.setX(0);\n this._arrowEnd.setY(0);\n this._arrowEnd.on(\"tick\", this._onArrowEndTick);\n super.addComponent(this._arrowEnd);\n }\n\n /**\n * Bound forwarder for the start arrow's `\"tick\"` event. Kept as a class\n * field so {@link off}-style detachment would have a stable reference.\n */\n private _onArrowStartTick = (): void => this.onArrowTick(-1);\n\n /**\n * Bound forwarder for the end arrow's `\"tick\"` event.\n */\n private _onArrowEndTick = (): void => this.onArrowTick(+1);\n\n /**\n * Computes the next scroll position one `_arrowStep` away from the current\n * one, clamps it to the valid range, and fires scroll listeners if it\n * changed. The owner's listener call back into `setMetrics` next frame,\n * which refreshes `atStart` / `atEnd` and updates the arrow disabled state.\n *\n * @param direction - `-1` for the start arrow, `+1` for the end arrow.\n */\n private onArrowTick(direction: -1 | 1): void {\n const maxScroll = Math.max(0, this._contentSize - this._viewportSize);\n const newPosition = Math.max(0, Math.min(maxScroll, this._scrollPosition + direction * this._arrowStep));\n\n if (newPosition !== this._scrollPosition) {\n this.emit(\"scroll\", newPosition);\n }\n }\n\n /**\n * Tears down both arrow buttons. Called when arrows are toggled off at\n * runtime; safe when no arrows are currently mounted.\n */\n private disposeArrows(): void {\n if (this._arrowStart) {\n super.removeComponent(this._arrowStart);\n this._arrowStart = null;\n }\n if (this._arrowEnd) {\n super.removeComponent(this._arrowEnd);\n this._arrowEnd = null;\n }\n }\n\n /**\n * Darkens the thumb fill when the cursor moves over it.\n */\n private _onThumbMouseOver = (): void => {\n this._thumb.setBackgroundColor(\"var(--ts-ui-scrollbar-thumb-hover, rgba(0, 0, 0, 0.55))\");\n };\n\n /**\n * Restores the thumb's resting fill when the cursor leaves it.\n */\n private _onThumbMouseOut = (): void => {\n this._thumb.setBackgroundColor(\"var(--ts-ui-scrollbar-thumb, rgba(0, 0, 0, 0.35))\");\n };\n\n /**\n * Initializes the scrollbar element and sets `touch-action: none` so the\n * browser doesn't try to page-scroll when the user drags on the track.\n *\n * @param element - Optional. The HTMLElement to initialize with.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n this.setTouchAction(\"none\");\n\n return this;\n }\n\n /**\n * Registers a listener for one of this scrollbar's events.\n *\n * @param event - `\"scroll\"` fires when the user changes the scroll\n * position by dragging the thumb, clicking the track, or pressing an\n * arrow button, receiving the new scroll position in pixels.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This scrollbar, for method chaining.\n */\n on(event: \"scroll\", listener: ScrollbarListener): this;\n on(event: ScrollbarEvent, 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 scrollbar, for method chaining.\n */\n off(event: ScrollbarEvent, 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.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"scroll\", position: number): void;\n protected emit(event: ScrollbarEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Pushes viewport/content metrics and the current scroll position into the\n * scrollbar. Recomputes the thumb size and position and hides the scrollbar\n * if the content fits in the viewport. When arrows are enabled, repositions\n * the end arrow against the current outer size and refreshes the\n * disabled-at-edge state on both arrows.\n *\n * @param viewportSize - The visible window size in pixels along the scroll axis.\n * @param contentSize - The total scrollable content size in pixels along the scroll axis.\n * @param scrollPosition - The current scroll offset in pixels.\n */\n setMetrics(viewportSize: number, contentSize: number, scrollPosition: number): this {\n this._viewportSize = viewportSize;\n this._contentSize = contentSize;\n this._scrollPosition = scrollPosition;\n\n const overflow = contentSize > viewportSize;\n this.setDisplayed(overflow);\n\n if (!overflow) {\n return this;\n }\n\n const trackLength = this.getTrackLength();\n if (trackLength <= 0) {\n return this;\n }\n\n const ratio = viewportSize / contentSize;\n const newThumbSize = Math.max(THUMB_MIN_SIZE, Math.floor(trackLength * ratio));\n if (this._thumbSize !== newThumbSize) {\n this._thumbSize = newThumbSize;\n this.setThumbSize(newThumbSize);\n }\n\n const maxScroll = Math.max(0, contentSize - viewportSize);\n const maxThumb = Math.max(0, trackLength - newThumbSize);\n const newThumbPos = maxScroll > 0 ? Math.round((scrollPosition / maxScroll) * maxThumb) : 0;\n if (this._thumbPos !== newThumbPos) {\n this._thumbPos = newThumbPos;\n this.setThumbPos(newThumbPos);\n }\n\n if (this._arrowsEnabled && this._arrowStart && this._arrowEnd) {\n // Position the end arrow against the current outer size — its\n // primary-axis origin sits at (outer - TRACK_WIDTH).\n const outer = this.isVertical() ? this.getHeight() : this.getWidth();\n const endPos = Math.max(0, outer - TRACK_WIDTH);\n if (this.isVertical()) {\n this._arrowEnd.setY(endPos);\n } else {\n this._arrowEnd.setX(endPos);\n }\n\n this._arrowStart.setDisabledState(scrollPosition <= 0);\n this._arrowEnd.setDisabledState(scrollPosition >= maxScroll);\n }\n\n return this;\n }\n\n /**\n * Returns the static track width in pixels (the cross-axis dimension).\n *\n * @returns The fixed track width.\n */\n getTrackWidth(): number {\n return TRACK_WIDTH;\n }\n\n /**\n * Returns the scrollbar's orientation.\n *\n * @returns `\"vertical\"` or `\"horizontal\"`.\n */\n getOrientation(): AxisOrientation {\n return this._orientation;\n }\n\n /**\n * Returns whether the arrow buttons at each end of the track are enabled.\n *\n * @returns `true` when arrows are rendered, `false` otherwise.\n */\n isArrowsEnabled(): boolean {\n return this._arrowsEnabled;\n }\n\n /**\n * Enables or disables the end-cap arrow buttons. Intended for\n * construction-time use via {@link ScrollbarOptions.arrowsEnabled};\n * runtime toggles are supported but tear down or build the arrow\n * components on the fly and re-run `setMetrics` against the cached\n * viewport / content / scroll-position triple so the thumb size / position\n * recompute against the new track length.\n *\n * @param enabled - `true` to render arrows, `false` to remove them.\n * @returns This scrollbar, for method chaining.\n */\n setArrowsEnabled(enabled: boolean): this {\n if (this._arrowsEnabled === enabled) {\n return this;\n }\n\n this._arrowsEnabled = enabled;\n\n if (enabled) {\n this.buildArrows();\n } else {\n this.disposeArrows();\n }\n\n this.setMetrics(this._viewportSize, this._contentSize, this._scrollPosition);\n\n return this;\n }\n\n /**\n * Returns the per-click scroll step in pixels used by the arrow buttons.\n *\n * @returns The cached arrow step.\n */\n getArrowStep(): number {\n return this._arrowStep;\n }\n\n /**\n * Sets the per-click scroll step in pixels used by the arrow buttons.\n * No-op when arrows are not enabled, except that the new value is cached\n * and applies on a subsequent {@link Scrollbar.setArrowsEnabled}`(true)`.\n *\n * @param px - The new step size in pixels.\n * @returns This scrollbar, for method chaining.\n */\n setArrowStep(px: number): this {\n this._arrowStep = px;\n\n return this;\n }\n\n /**\n * Returns true if this is a vertical scrollbar.\n *\n * @returns True for vertical, false for horizontal.\n */\n private isVertical(): boolean {\n return this._orientation === \"vertical\";\n }\n\n /**\n * Returns the length of the track along the scroll axis available for the\n * thumb to travel. Subtracts the two arrow regions when arrows are\n * enabled so the thumb travel range stays inside the track between them.\n */\n private getTrackLength(): number {\n const raw = this.isVertical() ? this.getHeight() : this.getWidth();\n const inset = this._arrowsEnabled ? 2 * TRACK_WIDTH : 0;\n\n return Math.max(0, raw - inset);\n }\n\n /**\n * Returns the primary-axis offset where the track region (thumb travel\n * area) starts. `TRACK_WIDTH` when arrows are enabled (skipping the start\n * arrow), `0` otherwise.\n */\n private getTrackOrigin(): number {\n return this._arrowsEnabled ? TRACK_WIDTH : 0;\n }\n\n /**\n * Sets the thumb's size along the scroll axis.\n *\n * @param size - The new thumb size in pixels.\n */\n private setThumbSize(size: number): void {\n if (this.isVertical()) {\n this._thumb.setHeight(size);\n } else {\n this._thumb.setWidth(size);\n }\n }\n\n /**\n * Sets the thumb's position along the scroll axis, offset by the track\n * origin so the thumb sits inside the track region between the arrows\n * when those are enabled.\n *\n * @param pos - The new thumb position in pixels, relative to the track region.\n */\n private setThumbPos(pos: number): void {\n const origin = this.getTrackOrigin();\n\n if (this.isVertical()) {\n this._thumb.setY(origin + pos);\n } else {\n this._thumb.setX(origin + pos);\n }\n }\n\n\n /**\n * Reads the client coordinate along the scroll axis from a mouse or touch\n * event, preferring the active touch on touchstart/touchmove and the\n * changed touch on touchend.\n *\n * @param e - A mouse or touch event.\n * @returns The primary-axis coordinate in viewport space.\n */\n private extractClientPrimary(e: MouseEvent | TouchEvent): number {\n const vertical = this.isVertical();\n const touchEvent = e as TouchEvent;\n\n if (touchEvent.touches !== undefined) {\n const t = touchEvent.touches.length > 0\n ? touchEvent.touches[0]\n : touchEvent.changedTouches[0];\n if (!t) {\n return 0;\n }\n return vertical ? t.clientY : t.clientX;\n }\n\n const mouse = e as MouseEvent;\n return vertical ? mouse.clientY : mouse.clientX;\n }\n\n /**\n * Captures the initial client coordinate and scroll position, then attaches\n * viewport listeners so the drag continues even when the pointer or finger\n * leaves the thumb.\n *\n * @param e - The mousedown or touchstart event on the thumb.\n */\n private _onDragStart = (e: MouseEvent | TouchEvent): void => {\n e.preventDefault();\n\n this._dragStartClient = this.extractClientPrimary(e);\n this._dragStartScroll = this._scrollPosition;\n\n Event.addViewportListener(this, \"mousemove\", this._onDragMove);\n Event.addViewportListener(this, \"mouseup\", this._onDragEnd);\n Event.addViewportListener(this, \"touchmove\", this._onDragMove);\n Event.addViewportListener(this, \"touchend\", this._onDragEnd);\n Event.addViewportListener(this, \"touchcancel\", this._onDragEnd);\n\n // Suppresses pointer events on document.body (not a Component) for the\n // duration of the drag so the cursor can't snag on other elements.\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"none\" } });\n };\n\n /**\n * Translates the client-axis delta into a scroll-position delta proportional\n * to the content/track ratio, clamps it, and fires scroll listeners.\n *\n * @param e - The viewport mousemove or touchmove event during a drag.\n * @returns `true` while a thumb drag is in progress, consuming the move so nothing else tracks the pointer.\n */\n private _onDragMove = (e: MouseEvent | TouchEvent): Event.ListenerResult => {\n const trackLength = this.getTrackLength();\n const maxScroll = Math.max(0, this._contentSize - this._viewportSize);\n const maxThumb = Math.max(0, trackLength - this._thumbSize);\n\n if (maxThumb <= 0) {\n return true;\n }\n\n const delta = this.extractClientPrimary(e) - this._dragStartClient;\n const scrollDelta = (delta / maxThumb) * maxScroll;\n const newPosition = Math.max(0, Math.min(maxScroll, this._dragStartScroll + scrollDelta));\n\n this.emit(\"scroll\", newPosition);\n\n return true;\n };\n\n /**\n * Removes viewport listeners and restores body pointer events.\n *\n * @param _e - The mouseup/touchend/touchcancel event ending the drag.\n * @returns `true`, consuming the release that ends the thumb drag.\n */\n private _onDragEnd = (_e: Event): Event.ListenerResult => {\n Event.removeViewportListener(this, \"mousemove\", this._onDragMove);\n Event.removeViewportListener(this, \"mouseup\", this._onDragEnd);\n Event.removeViewportListener(this, \"touchmove\", this._onDragMove);\n Event.removeViewportListener(this, \"touchend\", this._onDragEnd);\n Event.removeViewportListener(this, \"touchcancel\", this._onDragEnd);\n\n // Restores pointer events on document.body (not a Component) once the drag ends.\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"\" } });\n\n return true;\n };\n\n /**\n * Pages the scroll position by one viewport size when the user clicks or\n * taps the track outside the thumb. Events on the thumb itself are caught\n * by a separate listener and don't reach here. When arrows are enabled,\n * clicks that land inside an arrow region are ignored so the arrow\n * button's own handler is the sole authority on arrow-region clicks.\n *\n * @param e - The mousedown or touchstart event on the track.\n */\n private _onTrackClick = (e: MouseEvent | TouchEvent): void => {\n e.preventDefault();\n\n const vertical = this.isVertical();\n let click: number;\n\n const touchEvent = e as TouchEvent;\n if (touchEvent.touches !== undefined) {\n const t = touchEvent.touches.length > 0\n ? touchEvent.touches[0]\n : touchEvent.changedTouches[0];\n const el = this.getElement();\n if (!t || !el) {\n return;\n }\n const rect = DOM.source.getViewportRect(this);\n click = vertical ? t.clientY - rect.top : t.clientX - rect.left;\n } else {\n const mouse = e as MouseEvent;\n click = vertical ? mouse.offsetY : mouse.offsetX;\n }\n\n // When arrows are enabled, ignore clicks that landed inside either\n // arrow region — those are handled by the arrow's own mousedown\n // listener (which also stops propagation, but the touchstart path\n // does not, so we double-check here).\n const origin = this.getTrackOrigin();\n const outer = vertical ? this.getHeight() : this.getWidth();\n if (this._arrowsEnabled && (click < origin || click >= outer - TRACK_WIDTH)) {\n return;\n }\n\n // Subtract origin so the thumb-position comparison stays in the\n // track-relative coordinate space (matches `_thumbPos`).\n const trackClick = click - origin;\n const thumbCenter = this._thumbPos + this._thumbSize / 2;\n const direction = trackClick < thumbCenter ? -1 : 1;\n const maxScroll = Math.max(0, this._contentSize - this._viewportSize);\n const newPosition = Math.max(0, Math.min(maxScroll, this._scrollPosition + direction * this._viewportSize));\n\n this.emit(\"scroll\", newPosition);\n };\n}\n\nconst ScrollbarCallable = callable(Scrollbar);\ntype ScrollbarCallable = Scrollbar;\nexport {\n Scrollbar as _Scrollbar,\n ScrollbarCallable as Scrollbar\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./DOM-BeR95tE8.js";import{a as t,l as n}from"./Position-DRSlWn4Z.js";import{m as r,t as i,x as a}from"./Component-CHTzJxEf.js";import{t as o}from"./Text-Bni4icFY.js";import{t as s}from"./AbstractInput-DFWniHqq.js";var Label=class extends o{_forId;constructor(e,t,n){if(!t)throw Error(`Label requires a non-empty forId. Use Text for standalone text.`);super(e,{...n??{},tag:n?.tag??`label`}),this._forId=t}getForId(){return this._forId}setForId(t){if(!t)throw Error(`Label forId must be non-empty.`);this._forId=t;let n=this.getElement();return n&&e.sink.apply(n,{setAttr:{for:t}}),this}render(){let t=super.render();return e.sink.apply(t,{setAttr:{for:this._forId}}),t}},c=r(Label),l=4,u=16,d=0,f=100,p=1,Slider=class extends s{_track;_activeTrack;_thumb;_draggingPointer=null;constructor(e){if(super({...e??{}}),this._track=new i,this._track.setBackgroundColor(`var(--ts-ui-slider-track-bg, rgb(220, 220, 220))`),this._track.setBorderRadius(`999px`),this._track.setPointerEvents(`none`),this._activeTrack=new i,this._activeTrack.setBackgroundColor(`var(--ts-ui-slider-track-active-bg, rgb(30, 100, 200))`),this._activeTrack.setBorderRadius(`999px`),this._activeTrack.setPointerEvents(`none`),this._thumb=new i,this._thumb.setBackgroundColor(`var(--ts-ui-slider-thumb-bg, rgb(255, 255, 255))`),this._thumb.setBorderRadius(`50%`),this._thumb.setBorder(`1px solid var(--ts-ui-form-border, rgb(160, 160, 160))`),this._thumb.setShadow(`0 1px 2px rgba(0, 0, 0, 0.25)`),this._thumb.setPreferredSize({width:u,height:u}),this._thumb.setMaxSize({width:u,height:u}),this._thumb.setPointerEvents(`none`),this._track.addComponent(this._activeTrack),super.addComponent(this._track),super.addComponent(this._thumb),this.setPreferredSize({width:200,height:u}),this.setMaxSize({width:t,height:u}),this.setOutline(`none`),this.setCursor(`pointer`),this.getAria().setRole(`slider`),this.getAria().setTabIndex(0),this.getAria().setOrientation(`horizontal`),this.getAria().setValueMin(d),this.getAria().setValueMax(f),this.getAria().setValueNow(d),this.installInteraction(),this._options.minValue!==void 0&&this._options.min===void 0&&(this._options.min=this._options.minValue),this._options.maxValue!==void 0&&this._options.max===void 0&&(this._options.max=this._options.maxValue),this._options.min!==void 0&&this.applyMin(this._options.min),this._options.max!==void 0&&this.applyMax(this._options.max),this._options.orientation!==void 0&&this.applyOrientation(this._options.orientation),this._options.value!==void 0){let e=this.snap(this._options.value);this._options.value=e,this.applyValue(e)}else this.applyValue(this.getMin());this._options.enabled!==void 0&&this.applyEnabled(this._options.enabled),this._options.readOnly!==void 0&&this.applyReadOnly(this._options.readOnly)}applyOptions(e){return super.applyOptions(e),e.value!==void 0&&(this._options.value=e.value),e.min!==void 0&&(this._options.min=e.min),e.max!==void 0&&(this._options.max=e.max),e.minValue!==void 0&&(this._options.minValue=e.minValue),e.maxValue!==void 0&&(this._options.maxValue=e.maxValue),e.step!==void 0&&(this._options.step=e.step),e.largeStep!==void 0&&(this._options.largeStep=e.largeStep),e.orientation!==void 0&&(this._options.orientation=e.orientation),e.showTicks!==void 0&&(this._options.showTicks=e.showTicks),e.enabled!==void 0&&(this._options.enabled=e.enabled),e.readOnly!==void 0&&(this._options.readOnly=e.readOnly),this}getValue(){return this._options.value??this.getMin()}setValue(e){let t=this.snap(e);return t===this.getValue()?this:(this._options.value=t,this.applyValue(t),this.notifyChange(t),a.fireEvent(this,`input`),this)}getMin(){return this._options.min??d}setMin(e){return this._options.min=e,this.applyMin(e),this.applyValue(this.snap(this.getValue())),this}getMax(){return this._options.max??f}setMax(e){return this._options.max=e,this.applyMax(e),this.applyValue(this.snap(this.getValue())),this}setMinValue(e){return this.setMin(e)}getMinValue(){return this.getMin()}setMaxValue(e){return this.setMax(e)}getMaxValue(){return this.getMax()}getStep(){return this._options.step??p}setStep(e){return this._options.step=e,this}getLargeStep(){return this._options.largeStep??this.getStep()*10}setLargeStep(e){return this._options.largeStep=e,this}getOrientation(){return this._options.orientation??`horizontal`}setOrientation(e){return this._options.orientation=e,this.applyOrientation(e),this.applyValue(this.getValue()),this}isShowTicks(){return this._options.showTicks??!1}setShowTicks(e){return this._options.showTicks=e,this}on(e,t){return e===`action`?(a.addListener(this,`input`,t),this):super.on(e,t)}off(e,t){return e===`action`?(a.removeListener(this,`input`,t),this):super.off(e,t)}getBaseline(){let e=this.getPreferredSize();return e?e.height-2:null}doLayout(){let e=this.getInnerSize();if(!e)return this;let t=this.getOrientation()===`horizontal`,n=e.width,r=e.height,i=this.getMin(),a=this.getMax()-i,o=a>0?(this.getValue()-i)/a:0;if(t){let e=Math.round((r-l)/2);this._track.setX(0),this._track.setY(e),this._track.setSize({width:n,height:l});let t=Math.round(n*o);this._activeTrack.setX(0),this._activeTrack.setY(0),this._activeTrack.setSize({width:t,height:l});let i=Math.round((n-u)*o),a=Math.round((r-u)/2);this._thumb.setSize({width:u,height:u}),this._thumb.setX(i),this._thumb.setY(a)}else{let e=Math.round((n-l)/2);this._track.setX(e),this._track.setY(0),this._track.setSize({width:l,height:r});let t=Math.round(r*o);this._activeTrack.setX(0),this._activeTrack.setY(r-t),this._activeTrack.setSize({width:l,height:t});let i=Math.round((n-u)/2),a=Math.round((r-u)*(1-o));this._thumb.setSize({width:u,height:u}),this._thumb.setX(i),this._thumb.setY(a)}return this}installInteraction(){a.addListener(this,`pointerdown`,t=>{if(!this.isEnabled()||this.isReadOnly())return;t.preventDefault(),this.focus();let n=this.getElement();n&&(e.sink.setPointerCapture(n,t.pointerId),this._draggingPointer=t.pointerId),this.setValue(this.valueAtPointer(t))}),a.addListener(this,`pointermove`,e=>{this._draggingPointer===e.pointerId&&this.setValue(this.valueAtPointer(e))});let release=t=>{if(this._draggingPointer!==t.pointerId)return;let n=this.getElement();n&&e.source.hasPointerCapture(n,t.pointerId)&&e.sink.releasePointerCapture(n,t.pointerId),this._draggingPointer=null};a.addListener(this,`pointerup`,release),a.addListener(this,`pointercancel`,release),a.addListener(this,`lostpointercapture`,release),a.addListener(this,`keydown`,e=>{if(!this.isEnabled()||this.isReadOnly())return;let t=this.getStep(),n=this.getLargeStep(),r=this.getMin(),i=this.getMax();switch(e.key){case`ArrowRight`:case`ArrowUp`:e.preventDefault(),this.setValue(this.getValue()+t);break;case`ArrowLeft`:case`ArrowDown`:e.preventDefault(),this.setValue(this.getValue()-t);break;case`PageUp`:e.preventDefault(),this.setValue(this.getValue()+n);break;case`PageDown`:e.preventDefault(),this.setValue(this.getValue()-n);break;case`Home`:e.preventDefault(),this.setValue(r);break;case`End`:e.preventDefault(),this.setValue(i);break}})}valueAtPointer(t){if(!this.getElement())return this.getValue();let r=e.source.getViewportRect(this),i=this.getOrientation()===`horizontal`?r.width>0?(t.clientX-r.left)/r.width:0:r.height>0?1-(t.clientY-r.top)/r.height:0,a=n.clamp(i,0,1),o=this.getMin();return o+(this.getMax()-o)*a}snap(e){let t=this.getMin(),r=this.getMax(),i=this.getStep(),a=n.clamp(e,t,r);if(i<=0)return a;let o=t+Math.round((a-t)/i)*i;return n.clamp(o,t,r)}applyValue(e){this._options.value=e,this.getAria().setValueNow(e),this.scheduleLayout()}applyMin(e){this.getAria().setValueMin(e)}applyMax(e){this.getAria().setValueMax(e)}applyOrientation(e){this.getAria().setOrientation(e),e===`horizontal`?(this.setPreferredSize({width:200,height:u}),this.setMaxSize({width:t,height:u})):(this.setPreferredSize({width:u,height:200}),this.setMaxSize({width:u,height:t})),this.scheduleLayout()}applyEnabled(e){this.getAria().setDisabled(!e),this.getAria().setTabIndex(e?0:-1),this.setCursor(e?`pointer`:`default`)}applyReadOnly(e){this.getAria().setReadOnly(e)}},m=r(Slider);export{c as n,m as t};
|
|
2
|
-
//# sourceMappingURL=Slider-_JVvuQ8M.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Slider-_JVvuQ8M.js","names":[],"sources":["../../src/typescript/lib/component/input/Label.ts","../../src/typescript/lib/component/input/Slider.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Text, TextOptions } from \"~/component/input/Text.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Label}.\n *\n * @category Components\n */\nexport interface LabelOptions extends TextOptions {\n}\n\n/**\n * A label component backed by a `<label>` element.\n *\n * Always associated with a form control via the HTML `for` attribute.\n * For standalone text without a form-control association, use {@link Text} instead.\n *\n * @example\n * ```typescript\n * import { Label, TextField } from '@jimka/typescript-ui/component/input';\n*\n * const field = new TextField();\n * const label = new Label('Name:', field.getId());\n * panel.addComponent(label);\n * panel.addComponent(field);\n * ```\n *\n * @category Components\n */\nclass Label extends Text<LabelOptions> {\n\n private _forId: string;\n\n constructor(text: string, forId: string, options?: LabelOptions) {\n if (!forId) {\n throw new Error(\"Label requires a non-empty forId. Use Text for standalone text.\");\n }\n\n super(text, { ...(options ?? {}), tag: options?.tag ?? \"label\" });\n\n this._forId = forId;\n }\n\n /**\n * Returns the ID of the form element this label is associated with.\n *\n * @returns The value of the HTML `for` attribute.\n */\n public getForId() : string {\n return this._forId;\n }\n\n /**\n * Sets the for/htmlFor association and updates the DOM element.\n *\n * @param id - The ID of the form control this label should be associated with. Must be non-empty.\n *\n * @returns This component, for method chaining.\n */\n public setForId(id : string): this {\n if (!id) {\n throw new Error(\"Label forId must be non-empty.\");\n }\n\n this._forId = id;\n\n let element = this.getElement();\n if (!element) {\n return this;\n }\n\n DOM.sink.apply(element, { setAttr: { for: id } });\n\n return this;\n }\n\n /**\n * Renders the label element and sets its htmlFor attribute.\n *\n * @returns The created HTMLLabelElement with htmlFor initialised.\n */\n protected render(): Handle {\n let element = super.render();\n\n DOM.sink.apply(element, { setAttr: { for: this._forId } });\n\n return element;\n }\n}\n\nconst LabelCallable = callable(Label);\ntype LabelCallable = Label;\nexport {\n Label as _Label,\n LabelCallable as Label\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { UNBOUNDED } from \"~/primitive/Size.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { AxisOrientation } from \"~/primitive/Axis.js\";\n\n/**\n * Construction-time options for {@link Slider}.\n *\n * @category Components\n */\nexport interface SliderOptions extends AbstractInputOptions {\n value?: number;\n min?: number;\n max?: number;\n step?: number;\n largeStep?: number;\n orientation?: AxisOrientation;\n showTicks?: boolean;\n\n /** @deprecated use {@link SliderOptions.min} */\n minValue?: number;\n /** @deprecated use {@link SliderOptions.max} */\n maxValue?: number;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * slider's `action` shorthand to the inherited `change` / `binding`.\n */\n listeners?: {\n action?: () => void;\n change?: (value: number) => void;\n binding?: () => void;\n };\n}\n\nconst TRACK_THICKNESS = 4;\nconst THUMB_SIZE = 16;\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\nconst DEFAULT_STEP = 1;\n\n/**\n * A custom-drawn range slider rendered as a focusable `<div>` with\n * `role=\"slider\"`.\n *\n * The track + thumb are real Components; drag is implemented via\n * `pointerdown` + `setPointerCapture` so the cursor can leave the track\n * during a drag without losing the stream. Keyboard navigation follows the\n * WAI-ARIA Authoring Practices slider model (Arrow / PageUp / PageDown /\n * Home / End).\n *\n * @category Components\n */\nclass Slider<TOptions extends SliderOptions = SliderOptions>\n extends AbstractInput<number, TOptions>\n{\n private _track: Component;\n private _activeTrack: Component;\n private _thumb: Component;\n private _draggingPointer: number | null = null;\n\n /**\n * Constructs a Slider.\n *\n * @param options - Optional construction-time options.\n */\n constructor(options?: TOptions) {\n super({ ...(options ?? {}) } as TOptions);\n\n this._track = new Component();\n this._track.setBackgroundColor(\"var(--ts-ui-slider-track-bg, rgb(220, 220, 220))\");\n this._track.setBorderRadius(\"999px\");\n // Pointer-events pass through to the slider root so `addListener`\n // matches by id on every press, and the root's cursor is what shows\n // on hover anywhere over the control.\n this._track.setPointerEvents(\"none\");\n\n this._activeTrack = new Component();\n this._activeTrack.setBackgroundColor(\"var(--ts-ui-slider-track-active-bg, rgb(30, 100, 200))\");\n this._activeTrack.setBorderRadius(\"999px\");\n this._activeTrack.setPointerEvents(\"none\");\n\n this._thumb = new Component();\n this._thumb.setBackgroundColor(\"var(--ts-ui-slider-thumb-bg, rgb(255, 255, 255))\");\n this._thumb.setBorderRadius(\"50%\");\n this._thumb.setBorder(\"1px solid var(--ts-ui-form-border, rgb(160, 160, 160))\");\n this._thumb.setShadow(\"0 1px 2px rgba(0, 0, 0, 0.25)\");\n this._thumb.setPreferredSize({ width: THUMB_SIZE, height: THUMB_SIZE });\n this._thumb.setMaxSize({ width: THUMB_SIZE, height: THUMB_SIZE });\n this._thumb.setPointerEvents(\"none\");\n\n this._track.addComponent(this._activeTrack);\n super.addComponent(this._track);\n super.addComponent(this._thumb);\n\n this.setPreferredSize({ width: 200, height: THUMB_SIZE });\n this.setMaxSize({ width: UNBOUNDED, height: THUMB_SIZE });\n this.setOutline(\"none\");\n this.setCursor(\"pointer\");\n\n this.getAria().setRole(\"slider\");\n this.getAria().setTabIndex(0);\n this.getAria().setOrientation(\"horizontal\");\n this.getAria().setValueMin(DEFAULT_MIN);\n this.getAria().setValueMax(DEFAULT_MAX);\n this.getAria().setValueNow(DEFAULT_MIN);\n\n this.installInteraction();\n\n if (this._options.minValue !== undefined && this._options.min === undefined) {\n this._options.min = this._options.minValue;\n }\n\n if (this._options.maxValue !== undefined && this._options.max === undefined) {\n this._options.max = this._options.maxValue;\n }\n\n if (this._options.min !== undefined) {\n this.applyMin(this._options.min);\n }\n\n if (this._options.max !== undefined) {\n this.applyMax(this._options.max);\n }\n\n if (this._options.orientation !== undefined) {\n this.applyOrientation(this._options.orientation);\n }\n\n if (this._options.value !== undefined) {\n const snapped = this.snap(this._options.value);\n this._options.value = snapped;\n this.applyValue(snapped);\n } else {\n this.applyValue(this.getMin());\n }\n\n if (this._options.enabled !== undefined) {\n this.applyEnabled(this._options.enabled);\n }\n\n if (this._options.readOnly !== undefined) {\n this.applyReadOnly(this._options.readOnly);\n }\n }\n\n /**\n * Applies a {@link SliderOptions} bag. Inherited Component fields cascade\n * through `super.applyOptions`; slider-specific fields are stored pure on\n * `_options` so the constructor body can dispatch them after children\n * are built.\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @returns This component, for method chaining.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.value !== undefined) this._options.value = options.value;\n if (options.min !== undefined) this._options.min = options.min;\n if (options.max !== undefined) this._options.max = options.max;\n if (options.minValue !== undefined) this._options.minValue = options.minValue;\n if (options.maxValue !== undefined) this._options.maxValue = options.maxValue;\n if (options.step !== undefined) this._options.step = options.step;\n if (options.largeStep !== undefined) this._options.largeStep = options.largeStep;\n if (options.orientation !== undefined) this._options.orientation = options.orientation;\n if (options.showTicks !== undefined) this._options.showTicks = options.showTicks;\n if (options.enabled !== undefined) this._options.enabled = options.enabled;\n if (options.readOnly !== undefined) this._options.readOnly = options.readOnly;\n\n return this;\n }\n\n /**\n * Returns the current slider value.\n *\n * @returns The current numeric value.\n */\n getValue(): number {\n return this._options.value ?? this.getMin();\n }\n\n /**\n * Sets the slider value, clamped to `[min, max]` and snapped to `step`.\n * Notifies change and binding listeners only on a real transition.\n *\n * @param value - The desired value.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: number): this {\n const next = this.snap(value);\n if (next === this.getValue()) {\n return this;\n }\n\n this._options.value = next;\n this.applyValue(next);\n this.notifyChange(next);\n\n // Existing consumers wire to \"input\" via `on(\"action\", fn)`. Fire so\n // demos that read `slider.getValue()` from an `input` callback keep\n // working.\n Event.fireEvent(this, \"input\");\n\n return this;\n }\n\n /**\n * Returns the minimum value.\n *\n * @returns The current minimum.\n */\n getMin(): number {\n return this._options.min ?? DEFAULT_MIN;\n }\n\n /**\n * Sets the minimum value. The current value is reclamped if it falls\n * below the new minimum.\n *\n * @param value - The new minimum.\n *\n * @returns This component, for method chaining.\n */\n setMin(value: number): this {\n this._options.min = value;\n this.applyMin(value);\n this.applyValue(this.snap(this.getValue()));\n\n return this;\n }\n\n /**\n * Returns the maximum value.\n *\n * @returns The current maximum.\n */\n getMax(): number {\n return this._options.max ?? DEFAULT_MAX;\n }\n\n /**\n * Sets the maximum value. The current value is reclamped if it exceeds\n * the new maximum.\n *\n * @param value - The new maximum.\n *\n * @returns This component, for method chaining.\n */\n setMax(value: number): this {\n this._options.max = value;\n this.applyMax(value);\n this.applyValue(this.snap(this.getValue()));\n\n return this;\n }\n\n /**\n * Deprecated alias for {@link setMin}. Kept so existing demos compile;\n * remove in a follow-up cleanup once all consumers are migrated.\n *\n * @param value - The new minimum.\n *\n * @returns This component, for method chaining.\n *\n * @deprecated Use {@link setMin}.\n */\n setMinValue(value: number): this {\n return this.setMin(value);\n }\n\n /**\n * Deprecated alias for {@link getMin}.\n *\n * @returns The current minimum.\n *\n * @deprecated Use {@link getMin}.\n */\n getMinValue(): number {\n return this.getMin();\n }\n\n /**\n * Deprecated alias for {@link setMax}.\n *\n * @param value - The new maximum.\n *\n * @returns This component, for method chaining.\n *\n * @deprecated Use {@link setMax}.\n */\n setMaxValue(value: number): this {\n return this.setMax(value);\n }\n\n /**\n * Deprecated alias for {@link getMax}.\n *\n * @returns The current maximum.\n *\n * @deprecated Use {@link getMax}.\n */\n getMaxValue(): number {\n return this.getMax();\n }\n\n /**\n * Returns the step increment.\n *\n * @returns The current step.\n */\n getStep(): number {\n return this._options.step ?? DEFAULT_STEP;\n }\n\n /**\n * Sets the step increment used by keyboard navigation and value snapping.\n *\n * @param value - The new step.\n *\n * @returns This component, for method chaining.\n */\n setStep(value: number): this {\n this._options.step = value;\n\n return this;\n }\n\n /**\n * Returns the large-step increment used by PageUp / PageDown. Defaults to\n * `10 * step` when not explicitly set.\n *\n * @returns The current large-step.\n */\n getLargeStep(): number {\n return this._options.largeStep ?? this.getStep() * 10;\n }\n\n /**\n * Sets the PageUp / PageDown increment.\n *\n * @param value - The new large-step.\n *\n * @returns This component, for method chaining.\n */\n setLargeStep(value: number): this {\n this._options.largeStep = value;\n\n return this;\n }\n\n /**\n * Returns the current orientation.\n *\n * @returns `\"horizontal\"` or `\"vertical\"`.\n */\n getOrientation(): AxisOrientation {\n return this._options.orientation ?? \"horizontal\";\n }\n\n /**\n * Sets the slider orientation. Updates the ARIA attribute, the keyboard\n * model, and the track + thumb layout.\n *\n * @param orientation - `\"horizontal\"` or `\"vertical\"`.\n *\n * @returns This component, for method chaining.\n */\n setOrientation(orientation: AxisOrientation): this {\n this._options.orientation = orientation;\n this.applyOrientation(orientation);\n this.applyValue(this.getValue());\n\n return this;\n }\n\n /**\n * Returns whether tick marks are visible. (Not yet rendered visually —\n * the field is reserved for a follow-up.)\n *\n * @returns `true` when ticks should be shown.\n */\n isShowTicks(): boolean {\n return this._options.showTicks ?? false;\n }\n\n /**\n * Toggles tick mark visibility. Reserved option; no visual side effect\n * yet.\n *\n * @param value - `true` to show ticks.\n *\n * @returns This component, for method chaining.\n */\n setShowTicks(value: boolean): this {\n this._options.showTicks = value;\n\n return this;\n }\n\n /**\n * Registers a listener for one of this slider's events. `\"action\"` is a\n * typed semantic shorthand over {@link Event.addListener} for the\n * value-change event (the native `input`, fired on each drag step);\n * `\"change\"` and `\"binding\"` are the inherited {@link AbstractInput}\n * listener-bag events.\n *\n * @param event - The event name.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"action\", listener: Event.Listener): this;\n on(event: \"change\", listener: (value: number) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.addListener(this, \"input\", listener as Event.Listener);\n\n return this;\n }\n\n return super.on(event as \"change\", listener as (value: number) => void);\n }\n\n /**\n * Removes a previously registered listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.removeListener(this, \"input\", listener as Event.Listener);\n\n return this;\n }\n\n return super.off(event, listener);\n }\n\n /**\n * Returns a baseline near the bottom edge so the slider participates in\n * baseline alignment — sitting with its bottom roughly on the surrounding\n * text baseline — instead of being vertically centred in the row. The 2px\n * lift matches the other graphical controls so it doesn't sit below the\n * text descenders.\n *\n * @returns The preferred height minus 2, or `null` before a size is set.\n */\n getBaseline(): number | null {\n const size = this.getPreferredSize();\n\n return size ? size.height - 2 : null;\n }\n\n /**\n * Lays out the track, active fill, and thumb for the current size.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n const inner = this.getInnerSize();\n if (!inner) {\n return this;\n }\n\n const horizontal = this.getOrientation() === \"horizontal\";\n\n // `Component.setWidth` / `setHeight` clamp to the component's own\n // maxSize, so `inner` is already bounded by our `setMaxSize(_,\n // THUMB_SIZE)` (or `setMaxSize(THUMB_SIZE, _)` when vertical) — no\n // extra cross-axis clamp is needed here.\n const innerWidth = inner.width;\n const innerHeight = inner.height;\n const min = this.getMin();\n const max = this.getMax();\n const range = max - min;\n const fraction = range > 0 ? (this.getValue() - min) / range : 0;\n\n // doLayout only setX/setY/setSize on the children; their preferredSize\n // is a hint for parent layouts and never reaches their own DOM. Size\n // the thumb explicitly so it renders at THUMB_SIZE rather than\n // collapsing to its 2 × 2 border box.\n if (horizontal) {\n const trackTop = Math.round((innerHeight - TRACK_THICKNESS) / 2);\n this._track.setX(0);\n this._track.setY(trackTop);\n this._track.setSize({ width: innerWidth, height: TRACK_THICKNESS });\n\n const activeWidth = Math.round(innerWidth * fraction);\n this._activeTrack.setX(0);\n this._activeTrack.setY(0);\n this._activeTrack.setSize({ width: activeWidth, height: TRACK_THICKNESS });\n\n const thumbX = Math.round((innerWidth - THUMB_SIZE) * fraction);\n const thumbY = Math.round((innerHeight - THUMB_SIZE) / 2);\n this._thumb.setSize({ width: THUMB_SIZE, height: THUMB_SIZE });\n this._thumb.setX(thumbX);\n this._thumb.setY(thumbY);\n } else {\n const trackLeft = Math.round((innerWidth - TRACK_THICKNESS) / 2);\n this._track.setX(trackLeft);\n this._track.setY(0);\n this._track.setSize({ width: TRACK_THICKNESS, height: innerHeight });\n\n // Vertical slider: zero is at the bottom by convention.\n const activeHeight = Math.round(innerHeight * fraction);\n this._activeTrack.setX(0);\n this._activeTrack.setY(innerHeight - activeHeight);\n this._activeTrack.setSize({ width: TRACK_THICKNESS, height: activeHeight });\n\n const thumbX = Math.round((innerWidth - THUMB_SIZE) / 2);\n const thumbY = Math.round((innerHeight - THUMB_SIZE) * (1 - fraction));\n this._thumb.setSize({ width: THUMB_SIZE, height: THUMB_SIZE });\n this._thumb.setX(thumbX);\n this._thumb.setY(thumbY);\n }\n\n return this;\n }\n\n /**\n * Wires pointer drag (with setPointerCapture) and keyboard navigation.\n */\n private installInteraction(): void {\n // `pointer-events: none` on the inner visual children forwards pointer\n // hits to the root, so the exact-target `addListener` matches the\n // slider's id. `setPointerCapture` below then routes the move / up /\n // cancel stream to the same root element.\n Event.addListener(this, \"pointerdown\", (e: PointerEvent) => {\n if (!this.isEnabled() || this.isReadOnly()) {\n return;\n }\n\n e.preventDefault();\n this.focus();\n\n const element = this.getElement();\n if (element) {\n DOM.sink.setPointerCapture(element, e.pointerId);\n this._draggingPointer = e.pointerId;\n }\n\n this.setValue(this.valueAtPointer(e));\n });\n\n Event.addListener(this, \"pointermove\", (e: PointerEvent) => {\n if (this._draggingPointer !== e.pointerId) {\n return;\n }\n\n this.setValue(this.valueAtPointer(e));\n });\n\n const release = (e: PointerEvent): void => {\n if (this._draggingPointer !== e.pointerId) {\n return;\n }\n\n const element = this.getElement();\n if (element && DOM.source.hasPointerCapture(element, e.pointerId)) {\n DOM.sink.releasePointerCapture(element, e.pointerId);\n }\n\n this._draggingPointer = null;\n };\n\n Event.addListener(this, \"pointerup\", release);\n Event.addListener(this, \"pointercancel\", release);\n // Browser releases pointer capture on alt-tab / focus loss. Clear our\n // mirror so the next pointerdown starts clean and there's no stuck-drag.\n Event.addListener(this, \"lostpointercapture\", release);\n\n Event.addListener(this, \"keydown\", (e: KeyboardEvent) => {\n if (!this.isEnabled() || this.isReadOnly()) {\n return;\n }\n\n const step = this.getStep();\n const largeStep = this.getLargeStep();\n const min = this.getMin();\n const max = this.getMax();\n\n switch (e.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n e.preventDefault();\n this.setValue(this.getValue() + step);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n e.preventDefault();\n this.setValue(this.getValue() - step);\n break;\n case \"PageUp\":\n e.preventDefault();\n this.setValue(this.getValue() + largeStep);\n break;\n case \"PageDown\":\n e.preventDefault();\n this.setValue(this.getValue() - largeStep);\n break;\n case \"Home\":\n e.preventDefault();\n this.setValue(min);\n break;\n case \"End\":\n e.preventDefault();\n this.setValue(max);\n break;\n }\n });\n }\n\n /**\n * Converts a pointer position into the corresponding slider value.\n */\n private valueAtPointer(e: PointerEvent): number {\n const element = this.getElement();\n if (!element) {\n return this.getValue();\n }\n\n const rect = DOM.source.getViewportRect(this);\n const horizontal = this.getOrientation() === \"horizontal\";\n const fraction = horizontal\n ? (rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0)\n : (rect.height > 0 ? 1 - (e.clientY - rect.top) / rect.height : 0);\n\n const clamped = Util.clamp(fraction, 0, 1);\n const min = this.getMin();\n const max = this.getMax();\n\n return min + (max - min) * clamped;\n }\n\n /**\n * Clamps `value` to `[min, max]` and snaps to the nearest step boundary.\n */\n private snap(value: number): number {\n const min = this.getMin();\n const max = this.getMax();\n const step = this.getStep();\n\n const clamped = Util.clamp(value, min, max);\n\n if (step <= 0) {\n return clamped;\n }\n\n const snapped = min + Math.round((clamped - min) / step) * step;\n\n return Util.clamp(snapped, min, max);\n }\n\n /**\n * Updates the value-related ARIA state and re-runs layout to move the\n * thumb.\n */\n private applyValue(value: number): void {\n this._options.value = value;\n this.getAria().setValueNow(value);\n this.scheduleLayout();\n }\n\n /**\n * Pushes the new minimum into the ARIA cache.\n */\n private applyMin(value: number): void {\n this.getAria().setValueMin(value);\n }\n\n /**\n * Pushes the new maximum into the ARIA cache.\n */\n private applyMax(value: number): void {\n this.getAria().setValueMax(value);\n }\n\n /**\n * Reflects the orientation in ARIA, swaps the preferred size between\n * landscape and portrait, and forces a layout.\n */\n private applyOrientation(orientation: AxisOrientation): void {\n this.getAria().setOrientation(orientation);\n\n if (orientation === \"horizontal\") {\n this.setPreferredSize({ width: 200, height: THUMB_SIZE });\n this.setMaxSize({ width: UNBOUNDED, height: THUMB_SIZE });\n } else {\n this.setPreferredSize({ width: THUMB_SIZE, height: 200 });\n this.setMaxSize({ width: THUMB_SIZE, height: UNBOUNDED });\n }\n\n this.scheduleLayout();\n }\n\n /**\n * Reflects the enabled flag in the ARIA tree and tabindex.\n */\n protected applyEnabled(value: boolean): void {\n this.getAria().setDisabled(!value);\n this.getAria().setTabIndex(value ? 0 : -1);\n this.setCursor(value ? \"pointer\" : \"default\");\n }\n\n /**\n * Reflects the read-only flag in the ARIA tree.\n */\n protected applyReadOnly(value: boolean): void {\n this.getAria().setReadOnly(value);\n }\n}\n\nconst SliderCallable = callable(Slider);\ntype SliderCallable<TOptions extends SliderOptions = SliderOptions> = Slider<TOptions>;\nexport {\n Slider as _Slider,\n SliderCallable as Slider\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./DOM-BeR95tE8.js";import{i as t,n}from"./Position-DRSlWn4Z.js";import{m as r,r as i,x as a}from"./Component-CHTzJxEf.js";import{t as o}from"./Glyph-CnNslL95.js";import{t as s}from"./Button-B36rBMKC.js";import{xmark as c}from"./glyphs/solid/xmark.es.js";var ToggleButton=class extends s{get selectedStyleRule(){return this._selectedStyleRule??=this.createStyleRule(`.selected:not(:hover)`)}constructor(e,t){super(e),this.selectedStyleRule.set(`boxShadow`,`var(--ts-ui-toggle-selected-shadow, 2px 2px 1px inset grey)`),this.selectedStyleRule.set(`backgroundColor`,`var(--ts-ui-toggle-selected-bg, rgb(200, 200, 200))`),this.selectedStyleRule.set(`backgroundImage`,`var(--ts-ui-toggle-selected-bg, none)`),a.addListener(this,`click`,()=>this.onAction()),t&&this.applyOptions(t),this.applyListeners(t?.listeners)}applyOptions(e){return super.applyOptions(e),e.selected!==void 0&&this.setSelected(e.selected),this.isFlat()&&(this.setSelectedShadow(`var(--ts-ui-button-flat-pressed-shadow, inset 1px 1px 3px rgba(0, 0, 0, 0.25))`),this.setSelectedBackgroundColor(`var(--ts-ui-button-flat-pressed-bg, rgba(0, 0, 0, 0.10))`)),this}on(e,t){return a.addListener(this,`change`,t),this}off(e,t){return a.removeListener(this,`change`,t),this}isSelected(){return this._options.selected??!1}setSelected(t){this._options.selected=t,this.getAria().setPressed(t);let n=this.getElement();return n&&e.sink.apply(n,{toggleClass:{selected:t}}),this}setSelectedBackgroundColor(e){return this.selectedStyleRule.set(`backgroundColor`,e),this}setSelectedBackgroundImage(e){return this.selectedStyleRule.set(`backgroundImage`,e),this}setSelectedShadow(e){return this.selectedStyleRule.set(`boxShadow`,e),this}setSelectedBorder(e){let n=typeof e==`string`?{border:e}:e;return this.selectedStyleRule.setMany(t(n)),this}setFlat(e){return super.setFlat(e),this.isFlat()?(this.setSelectedShadow(`var(--ts-ui-button-flat-pressed-shadow, inset 1px 1px 3px rgba(0, 0, 0, 0.25))`),this.setSelectedBackgroundColor(`var(--ts-ui-button-flat-pressed-bg, rgba(0, 0, 0, 0.10))`)):(this.setSelectedShadow(`var(--ts-ui-toggle-selected-shadow, 2px 2px 1px inset grey)`),this.setSelectedBackgroundColor(`var(--ts-ui-toggle-selected-bg, rgb(200, 200, 200))`)),this}onAction(){this.setSelected(!this.isSelected()),a.fireEvent(this,`change`)}render(){let t=super.render();return e.sink.apply(t,{toggleClass:{selected:this.isSelected()}}),t}},l=r(ToggleButton);o.register(c);var u={preferredSize:{width:16,height:16},insets:new n(0,0,0,0),foregroundColor:`var(--ts-ui-close-button-fg, #555)`},TabCloseButton=class extends s{constructor(e){super(void 0,e,{...u,glyph:`xmark`})}},d=r(TabCloseButton),TabButton=class extends l{_closeable=!1;_closeButton=null;constructor(e,t){super(e),this._closeable=t?.closeable??!1,t&&this.applyOptions(t),this.applyTabStyling(),t?.glyph!==void 0&&this.setGlyph(t.glyph),this._closeable&&this.buildCloseButton(),this.applyListeners(t?.listeners)}applyTabStyling(){this.setBackgroundColor(`var(--ts-ui-tab-button-bg, #b8b8c3)`),this.setBackgroundImage(`var(--ts-ui-tab-button-bg, #b8b8c3)`),this.setBorder({borderTop:`var(--ts-ui-tab-button-border-top, var(--ts-ui-tab-button-border, none))`,borderRight:`var(--ts-ui-tab-button-border-right, var(--ts-ui-tab-button-border, none))`,borderBottom:`var(--ts-ui-tab-button-border-bottom, var(--ts-ui-tab-button-border, none))`,borderLeft:`var(--ts-ui-tab-button-border-left, var(--ts-ui-tab-button-border, none))`}),this.clearBorderRadius(),this.clearShadow(),this.setHoverBackgroundColor(`var(--ts-ui-tab-button-hover-bg, #c4c4cf)`),this.setHoverBackgroundImage(`var(--ts-ui-tab-button-hover-bg, #c4c4cf)`),this.setHoverShadow(`none`),this.setHoverBorder({borderTop:`var(--ts-ui-tab-button-hover-border-top, var(--ts-ui-tab-button-hover-border, none))`,borderRight:`var(--ts-ui-tab-button-hover-border-right, var(--ts-ui-tab-button-hover-border, none))`,borderBottom:`var(--ts-ui-tab-button-hover-border-bottom, var(--ts-ui-tab-button-hover-border, none))`,borderLeft:`var(--ts-ui-tab-button-hover-border-left, var(--ts-ui-tab-button-hover-border, none))`}),this.setSelectedBackgroundColor(`var(--ts-ui-tab-button-selected-bg, rgb(255, 255, 255))`),this.setSelectedBackgroundImage(`var(--ts-ui-tab-button-selected-bg, rgb(255, 255, 255))`),this.setSelectedShadow(`none`),this.setSelectedBorder({borderTop:`var(--ts-ui-tab-button-selected-border-top, var(--ts-ui-tab-button-selected-border, none))`,borderRight:`var(--ts-ui-tab-button-selected-border-right, var(--ts-ui-tab-button-selected-border, none))`,borderBottom:`var(--ts-ui-tab-button-selected-border-bottom, var(--ts-ui-tab-button-selected-border, none))`,borderLeft:`var(--ts-ui-tab-button-selected-border-left, var(--ts-ui-tab-button-selected-border, none))`})}buildCloseButton(){let t=new d;t.setBackgroundColor(`transparent`),t.setBackgroundImage(`none`),t.setHoverBackgroundColor(`var(--ts-ui-tab-close-hover-bg, rgba(0, 0, 0, 0.12))`),t.setHoverBackgroundImage(`none`),t.setHoverShadow(`none`),t.setBorderRadius(`3px`),t.clearBorder(),t.clearShadow(),t.setZIndex(1);let n=i.getResolvedScale();t.setWidth(n.tabClose),t.setHeight(n.tabClose),t.pinGlyphSize(n.tabCloseGlyph),e.sink.appendChild(this.getElement(!0),t.getElement(!0)),this._closeButton=t}getCloseButton(){return this._closeButton}isCloseable(){return this._closeable}},f=r(TabButton);export{d as n,l as r,f as t};
|
|
2
|
-
//# sourceMappingURL=TabButton-DEypdlZf.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TabButton-DEypdlZf.js","names":[],"sources":["../../src/typescript/lib/component/button/ToggleButton.ts","../../src/typescript/lib/component/button/TabCloseButton.ts","../../src/typescript/lib/component/button/TabButton.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { BorderOptions, borderToStyle } from \"~/primitive/Border.js\";\nimport { Button, ButtonOptions, ClickListener } from \"~/component/button/Button.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link ToggleButton}.\n *\n * @category Components\n */\nexport interface ToggleButtonOptions extends ButtonOptions {\n selected?: boolean;\n}\n\n/**\n * A toggle button component that switches between selected and unselected states on each click.\n *\n * Maintains a separate CSS rule for the `.selected` class to allow independent styling of\n * the active state, and fires a 'change' event whenever the selection state changes.\n *\n * @category Components\n */\nclass ToggleButton extends Button<ToggleButtonOptions> {\n\n // Lazy `.selected` rule. The slot is a fast-path cache for the wrapper\n // returned by Component's `createStyleRule` builder, which dedupes by\n // selector suffix — see Button's `_pressedStyleRule` for the full\n // explanation.\n private declare _selectedStyleRule?: StyleRule;\n private get selectedStyleRule(): StyleRule {\n return this._selectedStyleRule ??= this.createStyleRule(\".selected:not(:hover)\");\n }\n\n constructor(text: string, options?: ToggleButtonOptions) {\n // Button is a children-build class: it builds its inner text/HBox row\n // in its constructor body. We forward the positional `text` to super\n // (no options), queue the selected-state styles into the lazy rule,\n // then dispatch the consumer options through `applyOptions` at the\n // tail so Button's own option-backed setters run after children exist.\n super(text);\n\n this.selectedStyleRule.set(\"boxShadow\", \"var(--ts-ui-toggle-selected-shadow, 2px 2px 1px inset grey)\");\n this.selectedStyleRule.set(\"backgroundColor\", \"var(--ts-ui-toggle-selected-bg, rgb(200, 200, 200))\");\n this.selectedStyleRule.set(\"backgroundImage\", \"var(--ts-ui-toggle-selected-bg, none)\");\n\n Event.addListener(this, \"click\", () => this.onAction());\n\n if (options) {\n this.applyOptions(options);\n }\n\n // Button's constructor skipped the listener bag (it wires only a plain\n // Button); wire it here, after super() and applyOptions, as the leaf.\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Applies a {@link ToggleButtonOptions} bag, dispatching the toggle's\n * `selected` state after inherited Button/Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: ToggleButtonOptions): this {\n super.applyOptions(options);\n\n if (options.selected !== undefined) {\n this.setSelected(options.selected);\n }\n\n // Button's flat branch runs in `applyChromeOptions` and re-points only\n // Button's own hover/pressed rules — it never touches this toggle's\n // `.selected` rule. Re-point it here so a `new ToggleButton(text,\n // { flat: true })` reads depressed when selected, mirroring `setFlat`.\n if (this.isFlat()) {\n this.setSelectedShadow(\"var(--ts-ui-button-flat-pressed-shadow, inset 1px 1px 3px rgba(0, 0, 0, 0.25))\");\n this.setSelectedBackgroundColor(\"var(--ts-ui-button-flat-pressed-bg, rgba(0, 0, 0, 0.10))\");\n }\n\n return this;\n }\n\n /**\n * Registers a listener for this toggle button's `\"action\"` event — fired\n * when the toggle state changes. Overrides the inherited\n * [`Button`](/api/component/button/classes/Button) `on` so `\"action\"`\n * routes to the DOM `\"change\"` event (the toggle) rather than the base\n * `\"click\"`. A typed semantic shorthand over {@link Event.addListener}.\n *\n * @param event - The event name. Only `\"action\"` is accepted.\n * @param listener - The callback to invoke when the toggle state changes.\n *\n * @returns This button, for method chaining.\n */\n on(event: \"action\", listener: ClickListener): this;\n on(_event: \"action\", listener: ClickListener): this {\n Event.addListener(this, \"change\", listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered `\"action\"` listener. The exact\n * callback reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This button, for method chaining.\n */\n off(event: \"action\", listener: ClickListener): this;\n off(_event: \"action\", listener: ClickListener): this {\n Event.removeListener(this, \"change\", listener);\n\n return this;\n }\n\n /**\n * Returns whether the toggle button is currently in the selected state.\n *\n * @returns True if the button is currently selected.\n */\n isSelected(): boolean {\n return this._options.selected ?? false;\n }\n\n /**\n * Sets the selected state, toggles the 'selected' CSS class, and updates `aria-pressed`.\n *\n * @param value - True to select the button, false to deselect it.\n */\n setSelected(value: boolean) : this {\n this._options.selected = value;\n\n this.getAria().setPressed(value);\n\n let element = this.getElement();\n if (element) {\n DOM.sink.apply(element, { toggleClass: { selected: value } });\n }\n\n return this;\n }\n\n /**\n * Sets the background color for the `.selected` CSS rule, overriding the\n * default `--ts-ui-toggle-selected-bg` token for this instance.\n *\n * @param backgroundColor - A CSS color string.\n *\n * @returns This button, for method chaining.\n */\n setSelectedBackgroundColor(backgroundColor: string): this {\n this.selectedStyleRule.set(\"backgroundColor\", backgroundColor);\n\n return this;\n }\n\n /**\n * Sets the background image for the `.selected` CSS rule. Pairs with\n * {@link setSelectedBackgroundColor} so a plain colour drops out (invalid\n * as an image) and a gradient wins, matching the framework's background\n * colour/image auto-routing.\n *\n * @param backgroundImage - A CSS background-image string.\n *\n * @returns This button, for method chaining.\n */\n setSelectedBackgroundImage(backgroundImage: string): this {\n this.selectedStyleRule.set(\"backgroundImage\", backgroundImage);\n\n return this;\n }\n\n /**\n * Sets the box-shadow for the `.selected` CSS rule, overriding the default\n * `--ts-ui-toggle-selected-shadow` token for this instance.\n *\n * @param shadow - A CSS box-shadow string (e.g. `\"none\"`).\n *\n * @returns This button, for method chaining.\n */\n setSelectedShadow(shadow: string): this {\n this.selectedStyleRule.set(\"boxShadow\", shadow);\n\n return this;\n }\n\n /**\n * Sets the border for the `.selected` CSS rule, overriding the default\n * selected-state border for this instance. Accepts either a {@link BorderOptions}\n * bag or a CSS `border` shorthand string (sugar for `{ border: <string> }`,\n * e.g. `\"1px solid rgb(...)\"` or `\"none\"`).\n *\n * @param options - Border configuration, or a CSS `border` shorthand value.\n *\n * @returns This button, for method chaining.\n */\n setSelectedBorder(options: BorderOptions | string): this {\n const border = typeof options === \"string\" ? { border: options } : options;\n this.selectedStyleRule.setMany(borderToStyle(border));\n\n return this;\n }\n\n /**\n * Toggles the flat appearance, then re-points the `.selected:not(:hover)`\n * rule so a toggled-on flat button reads as depressed with the same sunken\n * treatment Button's flat `:active` state uses. Flattening points the\n * selected shadow/background at the `--ts-ui-button-flat-pressed-*` tokens;\n * un-flattening restores the default `--ts-ui-toggle-selected-*` tokens.\n *\n * @param value - The new flat state.\n *\n * @returns This button, for method chaining.\n */\n setFlat(value: boolean): this {\n super.setFlat(value);\n\n // Read the resolved state, not the requested `value`: `super.setFlat`\n // can refuse the flip (chromeless wins) or no-op on an unchanged value,\n // and the selected rule must track whatever flat state actually holds.\n if (this.isFlat()) {\n this.setSelectedShadow(\"var(--ts-ui-button-flat-pressed-shadow, inset 1px 1px 3px rgba(0, 0, 0, 0.25))\");\n this.setSelectedBackgroundColor(\"var(--ts-ui-button-flat-pressed-bg, rgba(0, 0, 0, 0.10))\");\n } else {\n this.setSelectedShadow(\"var(--ts-ui-toggle-selected-shadow, 2px 2px 1px inset grey)\");\n this.setSelectedBackgroundColor(\"var(--ts-ui-toggle-selected-bg, rgb(200, 200, 200))\");\n }\n\n return this;\n }\n\n /**\n * Toggles the selected state and fires a 'change' event when the button is clicked.\n */\n private onAction() {\n this.setSelected(!this.isSelected());\n\n Event.fireEvent(this, \"change\");\n }\n\n /**\n * Renders the button element and applies the 'selected' class if currently selected.\n *\n * @returns The created button element with the 'selected' class applied if appropriate.\n */\n render() {\n let element = super.render();\n DOM.sink.apply(element, { toggleClass: { selected: this.isSelected() } });\n return element;\n }\n}\n\nconst ToggleButtonCallable = callable(ToggleButton);\ntype ToggleButtonCallable = ToggleButton;\nexport {\n ToggleButton as _ToggleButton,\n ToggleButtonCallable as ToggleButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button, ButtonOptions } from \"~/component/button/Button.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { xmark } from \"~/glyphs/solid/xmark.js\";\n\nGlyph.register(xmark);\n\n/**\n * Construction-time options for {@link TabCloseButton}.\n *\n * @category Components\n */\nexport interface TabCloseButtonOptions extends ButtonOptions {\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * Layered on top of [`Button`](/api/component/button/classes/Button)'s own\n * defaults, then overlaid with consumer options before the seed `glyph`\n * pins the close icon.\n */\nconst _defaultTabCloseButtonOptions: Partial<TabCloseButtonOptions> = {\n preferredSize: { width: 16, height: 16 },\n insets: new Insets(0, 0, 0, 0),\n foregroundColor: \"var(--ts-ui-close-button-fg, #555)\",\n};\n\n/**\n * A compact close button displaying the `xmark` glyph, sized to sit flush inside a tab header.\n *\n * @category Components\n */\nclass TabCloseButton extends Button<TabCloseButtonOptions> {\n\n /**\n * Creates a TabCloseButton seeded with the `xmark` glyph and sized for use in a tab toolbar.\n */\n constructor(options?: TabCloseButtonOptions) {\n // The seed `glyph` is in the defaults bag — a caller-supplied\n // `options.glyph` still wins because Button resolves the effective\n // glyph as `options.glyph ?? _defaultOptions.glyph` at construction.\n super(undefined, options, {\n ..._defaultTabCloseButtonOptions,\n glyph: \"xmark\",\n });\n }\n}\n\nconst TabCloseButtonCallable = callable(TabCloseButton);\ntype TabCloseButtonCallable = TabCloseButton;\nexport {\n TabCloseButton as _TabCloseButton,\n TabCloseButtonCallable as TabCloseButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\nimport { ThemeManager } from \"~/core/Theme.js\";\nimport { ToggleButton, ToggleButtonOptions } from \"~/component/button/ToggleButton.js\";\nimport { TabCloseButton } from \"~/component/button/TabCloseButton.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link TabButton}.\n *\n * `text` (the label), `glyph`, and `selected` are inherited from\n * {@link ToggleButtonOptions}.\n *\n * @category Components\n */\nexport interface TabButtonOptions extends ToggleButtonOptions {\n /** When true, builds and overlays the close (✕) affordance. Default false. */\n closeable?: boolean;\n}\n\n/**\n * A tab-styled toggle button: a {@link ToggleButton} that paints its own\n * unselected/hover/selected fill from the `--ts-ui-tab-button-*` theme tokens\n * and optionally overlays a close (✕) affordance built from\n * {@link TabCloseButton}.\n *\n * `TabButton` is a [`TabBar`](/api/component/container/classes/TabBar)\n * collaborator, not a general-purpose button. It owns the per-tab styling and\n * close-button *construction* that the strip previously replayed inline for\n * every cell; the strip keeps every geometry concern — insets, writing mode,\n * min/max clamp, and the per-layout re-pin of the overlaid close button (which\n * is positioned via the exposed {@link getCloseButton}). It adds no selection\n * or roving-tab-index logic of its own — those slot through the inherited\n * `ToggleButton` surface.\n *\n * @category Components\n */\nclass TabButton extends ToggleButton {\n\n // Whether this tab carries a close affordance. Construction-time only (the\n // close button is built or not when the tab is created), so it is set once\n // in the constructor and never via an option-dispatched setter — hence a\n // plain field rather than a `declare`d cascade-written one.\n private _closeable: boolean = false;\n\n // The overlaid close button, or null when the tab is not closeable. Built\n // in the constructor and raw-appended onto this button's own element (the\n // standard overlay pattern); TabBar reads it to wire its \"action\" and to\n // position/re-pin it each layout.\n private _closeButton: TabCloseButton | null = null;\n\n /**\n * Builds a tab-styled toggle button with the given label, applying the\n * `--ts-ui-tab-button-*` fill/border/hover/selected styling and, when\n * `closeable` is set, building and overlaying the close affordance.\n *\n * @param text - The visible label for the tab.\n * @param options - Tab button options; `closeable` gates the close button.\n */\n constructor(text: string, options?: TabButtonOptions) {\n // ToggleButton (via Button) builds its inner text/HBox content row in\n // its constructor body, so forward the positional `text` to super\n // first; the styling setters below then fire on a fully-built button.\n super(text);\n\n this._closeable = options?.closeable ?? false;\n\n if (options) {\n this.applyOptions(options);\n }\n\n // Paint the tab styling AFTER applyOptions, not before: the cascade\n // re-applies Button's chrome defaults from _defaultButtonOptions (the\n // \"2px ridge\" border, the 4px border-radius, the button drop-shadow), so\n // tab styling applied earlier would be clobbered back to a rounded,\n // ridged, shadowed button. Running it last lets the flat tab tokens and\n // the cleared radius/shadow win — matching the legacy createBarEntry,\n // which styled a no-options ToggleButton with nothing applied afterward.\n this.applyTabStyling();\n\n // Button's constructor late-dispatches `setGlyph` from the options bag\n // once, before this subclass's `applyOptions` runs; a glyph passed to a\n // ToggleButton subclass is therefore only pure-written to `_options` and\n // never rendered. Dispatch it explicitly here, mirroring how TabBar\n // called `setGlyph(constraints.glyph)` after construction.\n if (options?.glyph !== undefined) {\n this.setGlyph(options.glyph);\n }\n\n if (this._closeable) {\n this.buildCloseButton();\n }\n\n // ToggleButton's constructor wired the listener bag from the options it\n // received — but `super(text)` above passed none, so it wired nothing.\n // Wire the bag here, as the leaf, after super() and applyOptions, so a\n // `new TabButton(name, { listeners: { action } })` is not silently\n // dropped (ARCHITECTURE.md, Event handling).\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Paints the tab's unselected, hover, and selected states from the\n * `--ts-ui-tab-button-*` theme tokens. The unselected fill routes the tab\n * token through both the background colour *and* image layer so Button's\n * inherited `--ts-ui-button-bg` gradient drops out (invalid as an image)\n * and the tab colour wins, killing the gradient bleed-through.\n */\n private applyTabStyling(): void {\n this.setBackgroundColor(\"var(--ts-ui-tab-button-bg, #b8b8c3)\");\n this.setBackgroundImage(\"var(--ts-ui-tab-button-bg, #b8b8c3)\");\n this.setBorder({\n borderTop: \"var(--ts-ui-tab-button-border-top, var(--ts-ui-tab-button-border, none))\",\n borderRight: \"var(--ts-ui-tab-button-border-right, var(--ts-ui-tab-button-border, none))\",\n borderBottom: \"var(--ts-ui-tab-button-border-bottom, var(--ts-ui-tab-button-border, none))\",\n borderLeft: \"var(--ts-ui-tab-button-border-left, var(--ts-ui-tab-button-border, none))\",\n });\n this.clearBorderRadius();\n this.clearShadow();\n\n // Hover state.\n this.setHoverBackgroundColor(\"var(--ts-ui-tab-button-hover-bg, #c4c4cf)\");\n this.setHoverBackgroundImage(\"var(--ts-ui-tab-button-hover-bg, #c4c4cf)\");\n this.setHoverShadow(\"none\");\n this.setHoverBorder({\n borderTop: \"var(--ts-ui-tab-button-hover-border-top, var(--ts-ui-tab-button-hover-border, none))\",\n borderRight: \"var(--ts-ui-tab-button-hover-border-right, var(--ts-ui-tab-button-hover-border, none))\",\n borderBottom: \"var(--ts-ui-tab-button-hover-border-bottom, var(--ts-ui-tab-button-hover-border, none))\",\n borderLeft: \"var(--ts-ui-tab-button-hover-border-left, var(--ts-ui-tab-button-hover-border, none))\",\n });\n\n // Selected (active) state.\n this.setSelectedBackgroundColor(\"var(--ts-ui-tab-button-selected-bg, rgb(255, 255, 255))\");\n this.setSelectedBackgroundImage(\"var(--ts-ui-tab-button-selected-bg, rgb(255, 255, 255))\");\n this.setSelectedShadow(\"none\");\n this.setSelectedBorder({\n borderTop: \"var(--ts-ui-tab-button-selected-border-top, var(--ts-ui-tab-button-selected-border, none))\",\n borderRight: \"var(--ts-ui-tab-button-selected-border-right, var(--ts-ui-tab-button-selected-border, none))\",\n borderBottom: \"var(--ts-ui-tab-button-selected-border-bottom, var(--ts-ui-tab-button-selected-border, none))\",\n borderLeft: \"var(--ts-ui-tab-button-selected-border-left, var(--ts-ui-tab-button-selected-border, none))\",\n });\n }\n\n /**\n * Builds the close (✕) affordance and overlays its element on this button's\n * own element. Transparent so the tab's background shows through, with a\n * faint rounded hover tint giving the ✕ its affordance. The ✕ is overlaid\n * (raw-appended) rather than enrolled in a layout so it floats at the corner\n * of the tab; TabBar pins its precise position each layout.\n */\n private buildCloseButton(): void {\n const closeButton = new TabCloseButton();\n\n // Transparent so the tab's own background shows through; a faint rounded\n // tint on hover gives the ✕ its affordance. `--ts-ui-tab-close-hover-bg`\n // has no themeToVars entry, so the inline rgba fallback is the actual\n // source of the value — keep it verbatim.\n closeButton.setBackgroundColor(\"transparent\");\n closeButton.setBackgroundImage(\"none\");\n closeButton.setHoverBackgroundColor(\"var(--ts-ui-tab-close-hover-bg, rgba(0, 0, 0, 0.12))\");\n closeButton.setHoverBackgroundImage(\"none\");\n closeButton.setHoverShadow(\"none\");\n closeButton.setBorderRadius(\"3px\");\n closeButton.clearBorder();\n closeButton.clearShadow();\n closeButton.setZIndex(1);\n\n // Shrink the ✕ glyph to roughly half the close-button hit box, centred —\n // the button stays the click target while the mark reads lighter. Pin it\n // (Glyph.setPreferredSize locks min/max too) so the line-height sync\n // never re-tracks the glyph to the title line height; TabBar's\n // per-layout re-pin keeps it at the base-scaled size.\n // Size the box here, not only in TabBar's per-layout pass. The ✕ is\n // raw-appended rather than enrolled in a layout, so nothing else gives\n // it a width until that pass runs — and a Button whose own width is\n // still unresolved centres its content at 0,0 and keeps it there, which\n // is what left the ✕ jammed into the corner on every tab that existed\n // at the strip's first layout.\n const closeScale = ThemeManager.getResolvedScale();\n\n closeButton.setWidth(closeScale.tabClose);\n closeButton.setHeight(closeScale.tabClose);\n closeButton.pinGlyphSize(closeScale.tabCloseGlyph);\n\n // Overlay it on this button's own element rather than enrolling it in a\n // layout (which would stretch it over the whole tab); TabBar pins it to\n // the right edge each layout.\n DOM.sink.appendChild(this.getElement(true)!, closeButton.getElement(true)!);\n\n this._closeButton = closeButton;\n }\n\n /**\n * Returns the overlaid close button, or `null` when this tab is not\n * closeable. TabBar wires its `\"action\"` event and positions/re-pins it on\n * each layout pass.\n *\n * @returns The close button, or `null`.\n */\n getCloseButton(): TabCloseButton | null {\n return this._closeButton;\n }\n\n /**\n * Returns whether this tab carries a close affordance. Construction-time\n * only — there is no runtime toggle.\n *\n * @returns True when the tab was built closeable.\n */\n isCloseable(): boolean {\n return this._closeable;\n }\n}\n\nconst TabButtonCallable = callable(TabButton);\ntype TabButtonCallable = TabButton;\nexport {\n TabButton as _TabButton,\n TabButtonCallable as TabButton\n};\n"],"mappings":"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"}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./DOM-BeR95tE8.js";import{l as t}from"./Position-DRSlWn4Z.js";import{_ as n,t as r,x as i}from"./Component-CHTzJxEf.js";import{t as a}from"./Text-Bni4icFY.js";var o=9e3,s=9800,c=1e4,l=11e3,u=12e3,d=new r,f;(function(t){let n=[],r=new WeakMap,a=0,f=null,p=!1;t.Band={Window:o,Popover:s,Dropdown:c,Dialog:l,Tooltip:u};function bandFor(e,t){return e?e.band:t}function register(e){if(r.has(e))return;let t=n.length>0?n[n.length-1]:null,i=e.isLayerRoot?.()?null:t,o=bandFor(i,e.getBand?.()??c),s={layer:e,parent:i,children:[],band:o,zIndex:o+ ++a};r.set(e,s),n.push(s),i&&i.children.push(s),p||installListeners()}t.register=register;function mount(t){e.source.contains(e.source.getDocumentElement(),t)||e.sink.appendChild(e.source.getDocumentElement(),t)}t.mount=mount;function unregister(e){let t=r.get(e);if(!t)return;r.delete(e);let i=n.indexOf(t);if(i>=0&&n.splice(i,1),t.parent){let e=t.parent.children.indexOf(t);e>=0&&t.parent.children.splice(e,1)}f===e&&(f=null),n.length===0&&p&&uninstallListeners()}t.unregister=unregister;function containsAcrossLayers(t,n){if(!n)return!1;let i=r.get(t);if(!i){let r=t.getLayerElement();return r?e.source.contains(r,n):!1}return nodeContains(i,n)}t.containsAcrossLayers=containsAcrossLayers;function getTopLayer(){return n.length>0?n[n.length-1].layer:null}t.getTopLayer=getTopLayer;function bringToFront(e){let t=r.get(e);t&&(restampSubtree(t),markActive(e))}t.bringToFront=bringToFront;function getZIndex(e){let t=r.get(e);return t?t.zIndex:c}t.getZIndex=getZIndex;function restampSubtree(e){let walk=e=>{e.zIndex=e.band+ ++a,e.layer.onZIndexChanged?.(e.zIndex);for(let t of e.children)walk(t)};walk(e)}function nodeContains(t,n){let r=t.layer.getLayerElement();if(r&&e.source.contains(r,n))return!0;for(let e of t.children)if(nodeContains(e,n))return!0;return!1}function markActive(e){f!==e&&(deactivateActive(),f=e,e.onActivate&&e.onActivate(!0))}function deactivateActive(){f&&f.onActivate&&f.onActivate(!1),f=null}function activatableAncestor(e){let t=e;for(;t;){if(t.layer.onActivate)return t.layer;t=t.parent}return null}function handleOutside(t,r){let i=n.slice().reverse(),a=!1,o=!1;for(let n of i){let i=n.layer.getDismissMode();if(containsAcrossLayers(n.layer,t)){markActive(activatableAncestor(n)??n.layer),a=!0,o=!0;break}let s=n.layer.getAnchorElement?.();if(s&&t&&e.source.contains(s,t)){o=!0;break}if(i===`manual`||i===`modal`||!(r?i===`blur`:i===`click-outside`||i===`blur`)){if(i===`modal`){o=!0;break}continue}n.layer.requestClose()}!a&&!o&&!r&&deactivateActive()}function onPointerDown(t){handleOutside(t.target===null?null:e.source.intern(t.target),!1)}function onWindowBlur(t){e.source.isWindow(t.target===null?null:e.source.intern(t.target))&&handleOutside(null,!1)}function onFocusIn(t){handleOutside(t.target===null?null:e.source.intern(t.target),!0)}function onKeyDown(e){if(e.key===`Escape`){for(let e=n.length-1;e>=0;e--)if(n[e].layer.getDismissMode()!==`manual`)return n[e].layer.requestClose(),!0}}function installListeners(){i.addViewportListener(d,`pointerdown`,onPointerDown),i.addViewportListener(d,`focusin`,onFocusIn),i.addViewportListener(d,`keydown`,onKeyDown),i.addViewportListener(d,`blur`,onWindowBlur),p=!0}function uninstallListeners(){i.removeViewportListener(d,`pointerdown`,onPointerDown),i.removeViewportListener(d,`focusin`,onFocusIn),i.removeViewportListener(d,`keydown`,onKeyDown),i.removeViewportListener(d,`blur`,onWindowBlur),p=!1}})(f||={});function positionAdjacent(e,t,n,r,i){let a=t+i,o=r-a,s=e-i;return n<=o?a:n<=s?e-n-i:o>=s?Math.max(0,r-n):0}function positionAligned(e,t,n,r,i){if(e>=i&&e+n<=r-i)return e;let a=t-n;return a>=i&&a+n<=r-i?a:clampAxis(e,n,r,i)}function clampAxis(e,n,r,i){return t.clamp(e,i,Math.max(i,r-n-i))}function positionFlexibleAnchored(e,t,n,r,i){let a=r-t-i,o=e-i;return n<=a||a>=o?{start:t,available:a}:{start:e-Math.min(n,o),available:o}}function positionAnchored(e,t,n,r){let i=r.gap??0,a=r.margin??0;if(r.axis===`vertical`){let r=positionAdjacent(e.top,e.bottom,t.height,n.height,i);return{x:positionAligned(e.left,e.right,t.width,n.width,a),y:r}}return{x:positionAdjacent(e.left,e.right,t.width,n.width,i),y:positionAligned(e.top,e.bottom,t.height,n.height,a)}}var p=100,m=class Tooltip extends r{_showAnimation=null;_hideAnimation=null;static instance=null;static showTimer=null;static attachments=new Map;static elementAttachments=new Map;static activeElement=null;static watching=!1;static _onAnchorWatch=()=>{Tooltip.activeElement!==null&&!e.source.isConnected(Tooltip.activeElement)&&Tooltip.hide()};static dismissing=!1;static H_PADDING=16;static V_PADDING=8;static MAX_WIDTH=300;static ITEM_HEIGHT=20;static CURSOR_LEFT=4;static CURSOR_RIGHT=12;static CURSOR_UP=0;static CURSOR_DOWN=12;static CURSOR_GAP=2;_text;_lineCount=1;_perLine=Tooltip.ITEM_HEIGHT;constructor(){super(),this.setVisible(!1),this.setZIndex(f.Band.Tooltip),this.setBackgroundColor(`var(--ts-ui-tooltip-bg, rgb(255, 255, 240))`),this.setForegroundColor(`var(--ts-ui-tooltip-color, rgb(0, 0, 0))`),this.setBorder({border:`1px solid var(--ts-ui-tooltip-border, rgb(180, 180, 100))`}),this.setShadow(`var(--ts-ui-tooltip-shadow, 1px 2px 4px rgba(0, 0, 0, 0.2))`),this.setBorderRadius(`var(--ts-ui-border-radius, 4px)`),this.setPointerEvents(`none`),this.setContain(`layout paint`),this._text=new a,this._text.setPointerEvents(`none`),this._text.setWhiteSpace(`pre-wrap`),this.addComponent(this._text)}static getInstance(){return Tooltip.instance||=new Tooltip,Tooltip.instance}static show(r,a,o){Tooltip.showTimer!==null&&(clearTimeout(Tooltip.showTimer),Tooltip.showTimer=null);let s=Tooltip.getInstance(),c=s.isVisible()&&!Tooltip.dismissing;s._text.setText(r);let l=r.split(`
|
|
2
|
-
`),u=l.reduce((e,n)=>Math.max(e,t.measureTextWidth(n)),0);s._perLine=s._perLineHeight();let d=Math.min(Tooltip.MAX_WIDTH,u+Tooltip.H_PADDING);if(u+Tooltip.H_PADDING>Tooltip.MAX_WIDTH){let t=d-Tooltip.H_PADDING,n=e.source.measureText(r,{maxWidth:t}).height;s._lineCount=Math.max(l.length,Math.round(n/s._perLine))}else s._lineCount=l.length;let m=s._lineCount*s._perLine+Tooltip.V_PADDING;s._lineCount===1&&(m=Math.max(m,Tooltip.ITEM_HEIGHT+Tooltip.V_PADDING)),s.setWidth(d),s.setHeight(m);let h=e.source.getViewportSize(),g=t.clamp(a,0,h.width),_=t.clamp(o,0,h.height);s.setX(positionAdjacent(g-Tooltip.CURSOR_LEFT,g+Tooltip.CURSOR_RIGHT,d,h.width,Tooltip.CURSOR_GAP)),s.setY(positionAdjacent(_-Tooltip.CURSOR_UP,_+Tooltip.CURSOR_DOWN,m,h.height,Tooltip.CURSOR_GAP));let v=s.getElement(!0);if(s.scheduleLayout(),f.mount(v),s.setVisible(!0),Tooltip.watching||=(i.addViewportListener(s,`mousemove`,Tooltip._onAnchorWatch),!0),Tooltip.dismissing=!1,c){e.sink.apply(v,{style:{opacity:`1`}});return}s._showAnimation?.cancel(),s._showAnimation=n.play(v,{from:{opacity:`0`},to:{opacity:`1`},durationMs:p,properties:[`opacity`]})}static hide(){Tooltip.showTimer!==null&&(clearTimeout(Tooltip.showTimer),Tooltip.showTimer=null);let e=Tooltip.getInstance(),t=e.getElement();Tooltip.watching&&=(i.removeViewportListener(e,`mousemove`,Tooltip._onAnchorWatch),!1),Tooltip.activeElement=null,t&&(Tooltip.dismissing=!0,e._hideAnimation?.cancel(),e._hideAnimation=n.play(t,{to:{opacity:`0`},durationMs:p,properties:[`opacity`],onComplete:()=>{Tooltip.dismissing&&(Tooltip.dismissing=!1,e.setVisible(!1),e.removeElement())}}))}static attach(e,t,n){Tooltip.detach(e);let r=0,a=0,mouseoverFn=i=>{Tooltip.showTimer===null&&(r=i.clientX,a=i.clientY,Tooltip.showTimer=setTimeout(()=>{Tooltip._applyColors(n),Tooltip.activeElement=e.getElement()??null,Tooltip.show(t,r,a),Tooltip.showTimer=null},500))},mousemoveFn=e=>{r=e.clientX,a=e.clientY},mouseoutFn=()=>{Tooltip.hide()},mousedownFn=()=>{Tooltip.hide()};i.addListener(e,`mouseover`,mouseoverFn),i.addListener(e,`mousemove`,mousemoveFn),i.addListener(e,`mouseout`,mouseoutFn),i.addListener(e,`mousedown`,mousedownFn),Tooltip.attachments.set(e.getId(),{text:t,colors:n,mouseoverFn,mousemoveFn,mouseoutFn,mousedownFn})}static detach(e){let t=e.getId(),n=Tooltip.attachments.get(t);n&&(i.removeListener(e,`mouseover`,n.mouseoverFn),i.removeListener(e,`mousemove`,n.mousemoveFn),i.removeListener(e,`mouseout`,n.mouseoutFn),i.removeListener(e,`mousedown`,n.mousedownFn),Tooltip.attachments.delete(t),Tooltip.hide())}static _applyColors(e){let t=Tooltip.getInstance();t.setBackgroundColor(e?.background??`var(--ts-ui-tooltip-bg, rgb(255, 255, 240))`),t.setForegroundColor(e?.color??`var(--ts-ui-tooltip-color, rgb(0, 0, 0))`),t.setBorder({border:`1px solid ${e?.border??`var(--ts-ui-tooltip-border, rgb(180, 180, 100))`}`})}static attachToElement(t,n){let r=Tooltip.elementAttachments.get(t),i=Tooltip.activeElement===t,a=r?r.lastX:0,o=r?r.lastY:0;Tooltip.detachElement(t);let s={text:n,showTimer:null,lastX:a,lastY:o,mouseoverFn:function onTooltipMouseOver(e){s.showTimer===null&&(s.lastX=e.clientX,s.lastY=e.clientY,s.showTimer=setTimeout(function onTooltipShowTimer(){Tooltip.activeElement=t,Tooltip.show(s.text,s.lastX,s.lastY),s.showTimer=null},500))},mousemoveFn:function onTooltipMouseMove(e){s.lastX=e.clientX,s.lastY=e.clientY},mouseoutFn:function onTooltipMouseOut(){s.showTimer!==null&&(clearTimeout(s.showTimer),s.showTimer=null),Tooltip.activeElement===t&&(Tooltip.activeElement=null),Tooltip.hide()},mousedownFn:function onTooltipMouseDown(){s.showTimer!==null&&(clearTimeout(s.showTimer),s.showTimer=null),Tooltip.hide()}};e.sink.addListener(t,`mouseover`,s.mouseoverFn),e.sink.addListener(t,`mousemove`,s.mousemoveFn),e.sink.addListener(t,`mouseout`,s.mouseoutFn),e.sink.addListener(t,`mousedown`,s.mousedownFn),Tooltip.elementAttachments.set(t,s),i&&(Tooltip.activeElement=t,Tooltip.show(n,s.lastX,s.lastY))}static detachElement(t){let n=Tooltip.elementAttachments.get(t);n&&(e.sink.removeListener(t,`mouseover`,n.mouseoverFn),e.sink.removeListener(t,`mousemove`,n.mousemoveFn),e.sink.removeListener(t,`mouseout`,n.mouseoutFn),e.sink.removeListener(t,`mousedown`,n.mousedownFn),n.showTimer!==null&&(clearTimeout(n.showTimer),n.showTimer=null),Tooltip.elementAttachments.delete(t),Tooltip.activeElement===t&&(Tooltip.activeElement=null))}_perLineHeight(){let{height:t}=e.source.measureText(`X`);return Math.ceil(t)}doLayout(){return super.doLayout(),this._text.setX(Tooltip.H_PADDING/2),this._text.setY(Tooltip.V_PADDING/2),this._text.setWidth(Math.max(0,this.getWidth()-Tooltip.H_PADDING)),this._text.setHeight(this._lineCount*this._perLine),this}destructor(){this._showAnimation?.cancel(),this._showAnimation=null,this._hideAnimation?.cancel(),this._hideAnimation=null,super.destructor()}};export{f as a,positionFlexibleAnchored as i,positionAligned as n,positionAnchored as r,m as t};
|
|
3
|
-
//# sourceMappingURL=Tooltip-BUy6uFKN.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e,o as t}from"./Position-DRSlWn4Z.js";import{d as n,f as r,m as i,p as a}from"./Component-CHTzJxEf.js";var BoxLayout=class extends n{_spacing=5;_stretching=!1;_mode=`preferred`;_overflowSizing=`preferred`;_justify=`start`;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.mode!==void 0&&this.setMode(e.mode),e.spacing!==void 0&&this.setComponentSpacing(e.spacing),e.stretching!==void 0&&this.setStretching(e.stretching),e.overflowSizing!==void 0&&this.setOverflowSizing(e.overflowSizing),e.justify!==void 0&&this.setJustify(e.justify)}getComponentSpacing(){return this._spacing||0}setComponentSpacing(e){return this._spacing=e||0,this}isStretching(){return this._stretching||!1}setStretching(e){return this._stretching=!!e,this}getMode(){return this._mode}setMode(e){return this._mode=e,this}getOverflowSizing(){return this._overflowSizing}setOverflowSizing(e){return this._overflowSizing=e,this}getJustify(){return this._justify}setJustify(e){return this._justify=e,this}aggregateMaxSize(n){let r=this.getContainer();if(!r)return null;let i=r.getPerimeterSize(),a=r.getLaidOutComponents(),o=n?i.left+i.right:i.top+i.bottom,s=n?i.top+i.bottom:i.left+i.right,c=o,l=0,u=!1,d=!1,f=0;for(let e of a){let r=e.getMaxSize();if(!r){u=!0,d=!0;continue}let i=n?r.width:r.height,a=n?r.height:r.width;t(i)?u=!0:this._mode===`equal`?f=Math.max(f,i):c+=i,t(a)?d=!0:l=Math.max(l,a)}this._mode===`equal`?c+=a.length*f+this._spacing*Math.max(0,a.length-1):c+=this._spacing*Math.max(0,a.length-1),l+=s;let p=u?e:c,m=d?e:l;return{width:n?p:m,height:n?m:p}}computeShrink(e,t,n,r){if(e<=n||r)return{remaining:Math.max(0,n-e),shrinkRatio:0};let i=e-n,a=e-t;return{remaining:0,shrinkRatio:a>0?Math.min(1,i/a):1}}justifyOffsets(e,t,n){let r=Math.max(0,t-e);return r===0||this._justify===`start`?{lead:0,gap:0}:this._justify===`center`?{lead:r/2,gap:0}:this._justify===`end`?{lead:r,gap:0}:this._justify===`between`?{lead:0,gap:n>1?r/(n-1):0}:{lead:n>0?r/(2*n):0,gap:n>0?r/n:0}}crossPlacement(e,t,n,r,i){let o=this.getLayoutConstraints(e),s=o?.fill??null,c=o?.anchor??null;if(i?s===a.VERTICAL||s===a.BOTH:s===a.HORIZONTAL||s===a.BOTH)return{offset:t,extent:n};let l=this.crossAnchorEdge(c,i);if(l===null)return null;let u=Math.min(r,n);return{offset:l===`lead`?t:t+(n-u),extent:u}}crossAnchorEdge(e,t){return e===null?null:t?e===r.NORTH||e===r.NORTHWEST||e===r.NORTHEAST?`lead`:e===r.SOUTH||e===r.SOUTHWEST||e===r.SOUTHEAST?`trail`:null:e===r.WEST||e===r.NORTHWEST||e===r.SOUTHWEST?`lead`:e===r.EAST||e===r.NORTHEAST||e===r.SOUTHEAST?`trail`:null}},VBox=class extends BoxLayout{_defaultComponentHeight=100;getContentBaseline(){let e=this.getContainer();if(!e)return null;let t=e.getLaidOutComponents();return t.length===0?null:t[0].getBaseline()}getPreferredSize(){let n=this.getContainer();if(!n)return null;let r=n.getPerimeterSize(),i=n.getLaidOutComponents();if(this._mode===`equal`){let e=0,t=0;for(let n in i){let r=i[n].getPreferredSize();r&&(e=Math.max(e,r.width),t=Math.max(t,r.height))}return{width:e+r.left+r.right,height:i.length*(t+this._spacing)-this._spacing+r.top+r.bottom}}let a=e,o=r.top+r.bottom;for(let e in i){let n=i[e].getPreferredSize();n&&(a=t(a)?Math.min(a,n.width):Math.max(a,n.width),o+=n.height)}return a+=r.left+r.right,o+=this._spacing*(i.length-1),{width:a,height:o}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents();if(this._mode===`equal`){let e=0,r=0;for(let t in n){let i=n[t].getMinSize();i&&(e=Math.max(e,i.width),r=Math.max(r,i.height))}return{width:e+t.left+t.right,height:n.length*(r+this._spacing)-this._spacing+t.top+t.bottom}}let r=0,i=t.top+t.bottom;for(let e in n){let t=n[e].getMinSize();t&&(r=Math.max(r,t.width),i+=t.height)}return r+=t.left+t.right,i+=this._spacing*(n.length-1),{width:r,height:i}}getMaxSize(){return this.aggregateMaxSize(!1)}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=e.getLaidOutComponents();if(t.length===0)return{width:0,height:0};let n=0;if(this._mode===`equal`){let e=0;for(let r of t){let t=r.getMinSize();t&&(n=Math.max(n,t.width),e=Math.max(e,t.height))}return{width:n,height:t.length*(e+this._spacing)-this._spacing}}let r=this._spacing*(t.length-1);for(let e of t){let t=e.getMinSize();t&&(n=Math.max(n,t.width),r+=t.height)}return{width:n,height:r}}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.inflateForOverflow(t);this._mode===`equal`?this.layoutEqualMode(n,t,a,r,i):this.layoutPreferredMode(n,a,r,i),this.reserveContentFrame()}layoutEqualMode(e,t,n,r,i){let o=this.computeEqualCellHeight(e,t.height,i),s=r.getLeft(),c=r.getTop();if(this.isStretching()){let t=n.width;for(let n of e)this.placeComponent(n,s,c,t,o,a.BOTH),c+=o+i;return}let l=r.getLeft(),u=n.width;for(let t of e){let e=t.getPreferredSize(),n=e?e.width:0,r=this.crossPlacement(t,l,u,n,!1);r?this.placeComponent(t,r.offset,c,r.extent,o,a.BOTH):this.placeComponent(t,s,c,n,o,a.BOTH),c+=o+i}}computeEqualCellHeight(e,t,n){let r=0,i=0;for(let t of e){let e=t.getMinSize();e&&(r=Math.max(r,e.height));let n=t.getPreferredSize();n&&(i=Math.max(i,n.height))}let a=(t-n*(e.length-1))/e.length;return a>=r?a:this.isOverflowingY()&&this._overflowSizing===`preferred`?Math.max(r,i):r}layoutPreferredMode(e,t,n,r){let{totalWeight:i,fixedPreferred:o,fixedMin:s}=this.measureFixedHeights(e,r),{remaining:c,shrinkRatio:l}=this.computeShrink(o,s,t.height,this.isOverflowingY()),u=[];for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0,n=t.getPreferredSize(),r=t.getMinSize(),a=t.getMaxSize();u.push(this.resolveChildHeight(n,r,a,e,i,c,l))}let d=0,f=0;if(i===0){let i=r*(e.length-1);for(let e of u)i+=e;let a=t.height-(n.getTop()+n.getBottom());({lead:d,gap:f}=this.justifyOffsets(i,a,e.length))}let p=n.getLeft(),m=t.width-(n.getLeft()+n.getRight()),h=n.getLeft(),g=n.getTop()+d;for(let n=0;n<e.length;n+=1){let i=e[n],o=i.getPreferredSize(),s=i.getMaxSize(),c;c=!o||this.isStretching()?t.width:Math.min(o.width,t.width),s&&(c=Math.min(c,s.width));let l=o?Math.min(o.width,m):m;s&&(l=Math.min(l,s.width));let d=this.crossPlacement(i,p,m,l,!1);d?this.placeComponent(i,d.offset,g,d.extent,u[n],a.BOTH):this.placeComponent(i,h,g,c,u[n],a.BOTH),g+=u[n],g+=r+f}}measureFixedHeights(e,t){let n=0,r=t*(e.length-1),i=t*(e.length-1);for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0;if(e>0)n+=e;else{let e=t.getPreferredSize(),n=t.getMinSize();r+=this.preferredChildHeight(e,n),i+=n?n.height:0}}return{totalWeight:n,fixedPreferred:r,fixedMin:i}}preferredChildHeight(e,t){let n=(e?e.height:void 0)??(t&&t.height>0?t.height:void 0)??this._defaultComponentHeight;return t?Math.max(n,t.height):n}resolveChildHeight(e,t,n,r,i,a,o){let s;if(r>0&&i>0)s=r/i*a;else{let n=this.preferredChildHeight(e,t);s=n-o*(n-(t?t.height:0))}return t&&(s=Math.max(s,t.height)),n&&(s=Math.min(s,n.height)),s}},o=i(VBox);export{o as n,BoxLayout as r,VBox as t};
|
|
2
|
-
//# sourceMappingURL=VBox-Dr7Ge9M6.js.map
|