@accelint/design-toolkit 9.13.0 → 10.1.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/catalog-info.yaml +1 -1
- package/dist/components/accordion/group.d.ts +2 -2
- package/dist/components/accordion/index.d.ts +2 -2
- package/dist/components/accordion/panel.d.ts +2 -2
- package/dist/components/accordion/trigger.d.ts +2 -2
- package/dist/components/action-bar/index.d.ts +2 -2
- package/dist/components/audio/index.d.ts +2 -2
- package/dist/components/avatar/context.d.ts +2 -2
- package/dist/components/avatar/index.d.ts +2 -2
- package/dist/components/badge/context.d.ts +4 -4
- package/dist/components/breadcrumbs/index.d.ts +2 -2
- package/dist/components/breadcrumbs/item.d.ts +2 -2
- package/dist/components/button/context.d.ts +8 -8
- package/dist/components/button/index.d.ts +2 -2
- package/dist/components/button/link.d.ts +2 -2
- package/dist/components/button/toggle.d.ts +2 -2
- package/dist/components/carousel/context.d.ts +4 -4
- package/dist/components/carousel/gallery.d.ts +2 -2
- package/dist/components/carousel/index.d.ts +2 -2
- package/dist/components/carousel/navigation.d.ts +3 -3
- package/dist/components/carousel/position.d.ts +2 -2
- package/dist/components/carousel/select.d.ts +2 -2
- package/dist/components/carousel/viewer.d.ts +2 -2
- package/dist/components/checkbox/context.d.ts +3 -3
- package/dist/components/checkbox/group.d.ts +2 -2
- package/dist/components/checkbox/index.d.ts +2 -2
- package/dist/components/chip/context.d.ts +4 -4
- package/dist/components/chip/deletable.d.ts +2 -2
- package/dist/components/chip/index.d.ts +2 -2
- package/dist/components/chip/list.d.ts +4 -4
- package/dist/components/chip/selectable.d.ts +2 -2
- package/dist/components/classification-badge/context.d.ts +4 -4
- package/dist/components/classification-badge/index.d.ts +2 -2
- package/dist/components/classification-banner/context.d.ts +4 -4
- package/dist/components/classification-banner/index.d.ts +2 -2
- package/dist/components/clock/index.d.ts +2 -2
- package/dist/components/color-picker/index.d.ts +2 -2
- package/dist/components/combobox-field/context.d.ts +4 -4
- package/dist/components/combobox-field/index.d.ts +2 -2
- package/dist/components/coordinate-field/context.d.ts +6 -6
- package/dist/components/coordinate-field/index.d.ts +2 -2
- package/dist/components/coordinate-field/segment.d.ts +2 -2
- package/dist/components/date-field/index.d.ts +2 -2
- package/dist/components/date-field/index.js.map +1 -1
- package/dist/components/deferred-collection/index.d.ts +2 -2
- package/dist/components/details-list/context.d.ts +4 -4
- package/dist/components/details-list/index.d.ts +2 -2
- package/dist/components/details-list/label.d.ts +2 -2
- package/dist/components/details-list/value.d.ts +2 -2
- package/dist/components/dialog/content.d.ts +2 -2
- package/dist/components/dialog/context.d.ts +2 -2
- package/dist/components/dialog/footer.d.ts +2 -2
- package/dist/components/dialog/index.d.ts +2 -2
- package/dist/components/dialog/title.d.ts +2 -2
- package/dist/components/divider/context.d.ts +4 -4
- package/dist/components/divider/index.d.ts +2 -2
- package/dist/components/drawer/back.d.ts +2 -2
- package/dist/components/drawer/close.d.ts +2 -2
- package/dist/components/drawer/content.d.ts +2 -2
- package/dist/components/drawer/context.d.ts +2 -2
- package/dist/components/drawer/footer.d.ts +2 -2
- package/dist/components/drawer/header-title.d.ts +2 -2
- package/dist/components/drawer/header.d.ts +2 -2
- package/dist/components/drawer/index.d.ts +2 -2
- package/dist/components/drawer/layout-main.d.ts +2 -2
- package/dist/components/drawer/layout.d.ts +2 -2
- package/dist/components/drawer/menu-item.d.ts +2 -2
- package/dist/components/drawer/menu.d.ts +2 -2
- package/dist/components/drawer/panel.d.ts +2 -2
- package/dist/components/drawer/trigger.d.ts +2 -2
- package/dist/components/drawer/view.d.ts +2 -2
- package/dist/components/flashcard/index.d.ts +9 -9
- package/dist/components/floating-card/constants.d.ts +26 -0
- package/dist/components/floating-card/constants.js +40 -0
- package/dist/components/floating-card/constants.js.map +1 -0
- package/dist/components/floating-card/context.d.ts +38 -6
- package/dist/components/floating-card/context.js +24 -3
- package/dist/components/floating-card/context.js.map +1 -1
- package/dist/components/floating-card/hooks/use-card-layout.d.ts +36 -0
- package/dist/components/floating-card/hooks/use-card-layout.js +106 -0
- package/dist/components/floating-card/hooks/use-card-layout.js.map +1 -0
- package/dist/components/floating-card/hooks/use-drag.d.ts +62 -0
- package/dist/components/floating-card/hooks/use-drag.js +100 -0
- package/dist/components/floating-card/hooks/use-drag.js.map +1 -0
- package/dist/components/floating-card/hooks/use-mouse-interaction.d.ts +58 -0
- package/dist/components/floating-card/hooks/use-mouse-interaction.js +91 -0
- package/dist/components/floating-card/hooks/use-mouse-interaction.js.map +1 -0
- package/dist/components/floating-card/hooks/use-resize.d.ts +56 -0
- package/dist/components/floating-card/hooks/use-resize.js +98 -0
- package/dist/components/floating-card/hooks/use-resize.js.map +1 -0
- package/dist/components/floating-card/index.d.ts +6 -2
- package/dist/components/floating-card/index.js +24 -32
- package/dist/components/floating-card/index.js.map +1 -1
- package/dist/components/floating-card/panel.d.ts +69 -0
- package/dist/components/floating-card/panel.js +111 -0
- package/dist/components/floating-card/panel.js.map +1 -0
- package/dist/components/floating-card/provider.d.ts +10 -6
- package/dist/components/floating-card/provider.js +159 -153
- package/dist/components/floating-card/provider.js.map +1 -1
- package/dist/components/floating-card/styles.module.css +93 -39
- package/dist/components/floating-card/types.d.ts +51 -10
- package/dist/components/floating-card/utils.d.ts +8 -85
- package/dist/components/floating-card/utils.js +12 -38
- package/dist/components/floating-card/utils.js.map +1 -1
- package/dist/components/gantt/components/base-elements/range.d.ts +2 -2
- package/dist/components/gantt/components/containers/external/gantt-content-container/index.d.ts +2 -2
- package/dist/components/gantt/components/containers/external/gantt-panel-container/index.d.ts +2 -2
- package/dist/components/gantt/components/containers/internal/index.d.ts +2 -2
- package/dist/components/gantt/components/containers/internal/layout-container/index.d.ts +2 -2
- package/dist/components/gantt/components/containers/internal/virtualized-content-height-container/index.d.ts +2 -2
- package/dist/components/gantt/components/content-row/block.d.ts +2 -2
- package/dist/components/gantt/components/content-row/bracket.d.ts +3 -3
- package/dist/components/gantt/components/content-row/icon-marker.d.ts +2 -2
- package/dist/components/gantt/components/content-row/index.d.ts +2 -2
- package/dist/components/gantt/components/content-row/marker.d.ts +2 -2
- package/dist/components/gantt/components/content-row/spacer.d.ts +2 -2
- package/dist/components/gantt/components/current-time/index.d.ts +2 -2
- package/dist/components/gantt/components/header/index.d.ts +3 -3
- package/dist/components/gantt/components/panel-row/index.d.ts +2 -2
- package/dist/components/gantt/components/rows-virtualizer/index.d.ts +3 -3
- package/dist/components/gantt/components/timeline/index.d.ts +2 -2
- package/dist/components/gantt/components/timeline-chunk/index.d.ts +3 -3
- package/dist/components/gantt/context/index.d.ts +4 -4
- package/dist/components/gantt/context/store/index.d.ts +4 -4
- package/dist/components/gantt/context/temporal-data/index.d.ts +4 -4
- package/dist/components/gantt/hooks/use-layout-subscription/index.js +8 -8
- package/dist/components/gantt/hooks/use-layout-subscription/index.js.map +1 -1
- package/dist/components/hero/context.d.ts +2 -2
- package/dist/components/hero/index.d.ts +2 -2
- package/dist/components/hero/subtitle.d.ts +3 -3
- package/dist/components/hero/title.d.ts +2 -2
- package/dist/components/hotkey/context.d.ts +4 -4
- package/dist/components/hotkey/index.d.ts +2 -2
- package/dist/components/hotkey/set.d.ts +2 -2
- package/dist/components/icon/context.d.ts +4 -4
- package/dist/components/icon/index.d.ts +2 -2
- package/dist/components/input/index.d.ts +2 -2
- package/dist/components/kanban/card-body.d.ts +2 -2
- package/dist/components/kanban/card-header-actions.d.ts +2 -2
- package/dist/components/kanban/card-header-title.d.ts +2 -2
- package/dist/components/kanban/card-header.d.ts +2 -2
- package/dist/components/kanban/card.d.ts +2 -2
- package/dist/components/kanban/column-actions.d.ts +2 -2
- package/dist/components/kanban/column-container.d.ts +2 -2
- package/dist/components/kanban/column-content.d.ts +2 -2
- package/dist/components/kanban/column-header-actions.d.ts +2 -2
- package/dist/components/kanban/column-header-drag-handle.d.ts +2 -2
- package/dist/components/kanban/column-header-title.d.ts +2 -2
- package/dist/components/kanban/column-header.d.ts +2 -2
- package/dist/components/kanban/column.d.ts +2 -2
- package/dist/components/kanban/context.d.ts +2 -2
- package/dist/components/kanban/header-actions.d.ts +2 -2
- package/dist/components/kanban/header-search.d.ts +2 -2
- package/dist/components/kanban/header-title.d.ts +2 -2
- package/dist/components/kanban/header.d.ts +2 -2
- package/dist/components/kanban/kanban.d.ts +2 -2
- package/dist/components/label/context.d.ts +4 -4
- package/dist/components/label/index.d.ts +2 -2
- package/dist/components/lines/index.d.ts +2 -2
- package/dist/components/link/context.d.ts +2 -2
- package/dist/components/link/index.d.ts +2 -2
- package/dist/components/list/context.d.ts +2 -2
- package/dist/components/list/index.d.ts +2 -2
- package/dist/components/list/item-content.d.ts +2 -2
- package/dist/components/list/item-description.d.ts +2 -2
- package/dist/components/list/item-title.d.ts +2 -2
- package/dist/components/list/item.d.ts +2 -2
- package/dist/components/media-controls/context.d.ts +4 -4
- package/dist/components/media-controls/fullscreen-button.d.ts +2 -2
- package/dist/components/media-controls/index.d.ts +2 -2
- package/dist/components/media-controls/mute-button.d.ts +2 -2
- package/dist/components/media-controls/play-button.d.ts +2 -2
- package/dist/components/media-controls/playback-rate.d.ts +2 -2
- package/dist/components/media-controls/seek-button.d.ts +2 -2
- package/dist/components/media-controls/time-display.d.ts +2 -2
- package/dist/components/media-controls/time-range.d.ts +2 -2
- package/dist/components/media-controls/volume-slider.d.ts +2 -2
- package/dist/components/menu/context.d.ts +2 -2
- package/dist/components/menu/index.d.ts +2 -2
- package/dist/components/menu/item-description.d.ts +2 -2
- package/dist/components/menu/item-label.d.ts +2 -2
- package/dist/components/menu/item.d.ts +2 -2
- package/dist/components/menu/section.d.ts +2 -2
- package/dist/components/menu/separator.d.ts +2 -2
- package/dist/components/menu/submenu.d.ts +2 -2
- package/dist/components/notice/index.d.ts +2 -2
- package/dist/components/notice/list.d.ts +2 -2
- package/dist/components/notice/notice-icon.d.ts +2 -2
- package/dist/components/options/context.d.ts +2 -2
- package/dist/components/options/index.d.ts +2 -2
- package/dist/components/options/item-content.d.ts +2 -2
- package/dist/components/options/item-description.d.ts +2 -2
- package/dist/components/options/item-label.d.ts +2 -2
- package/dist/components/options/item.d.ts +2 -2
- package/dist/components/options/section.d.ts +2 -2
- package/dist/components/pagination/context.d.ts +2 -2
- package/dist/components/pagination/index.d.ts +2 -2
- package/dist/components/pagination/next.d.ts +2 -2
- package/dist/components/pagination/pages.d.ts +2 -2
- package/dist/components/pagination/prev.d.ts +2 -2
- package/dist/components/popover/content.d.ts +2 -2
- package/dist/components/popover/footer.d.ts +2 -2
- package/dist/components/popover/index.d.ts +2 -2
- package/dist/components/popover/title.d.ts +2 -2
- package/dist/components/popover/trigger.d.ts +2 -2
- package/dist/components/query-builder/action-element.d.ts +2 -2
- package/dist/components/query-builder/combinator-selector.d.ts +2 -2
- package/dist/components/query-builder/index.d.ts +2 -2
- package/dist/components/query-builder/rule-group.d.ts +4 -4
- package/dist/components/query-builder/rule.d.ts +2 -2
- package/dist/components/query-builder/value-editor.d.ts +2 -2
- package/dist/components/query-builder/value-selector.d.ts +2 -2
- package/dist/components/radio/context.d.ts +3 -3
- package/dist/components/radio/group.d.ts +2 -2
- package/dist/components/radio/index.d.ts +2 -2
- package/dist/components/search-field/context.d.ts +2 -2
- package/dist/components/search-field/index.d.ts +2 -2
- package/dist/components/select-field/context.d.ts +4 -4
- package/dist/components/select-field/index.d.ts +2 -2
- package/dist/components/sidenav/avatar.d.ts +2 -2
- package/dist/components/sidenav/content.d.ts +2 -2
- package/dist/components/sidenav/context.d.ts +2 -2
- package/dist/components/sidenav/footer.d.ts +2 -2
- package/dist/components/sidenav/header.d.ts +2 -2
- package/dist/components/sidenav/index.d.ts +2 -2
- package/dist/components/sidenav/item.d.ts +2 -2
- package/dist/components/sidenav/link.d.ts +2 -2
- package/dist/components/sidenav/menu-item.d.ts +2 -2
- package/dist/components/sidenav/menu.d.ts +2 -2
- package/dist/components/sidenav/trigger.d.ts +2 -2
- package/dist/components/skeleton/index.d.ts +2 -2
- package/dist/components/slider/index.d.ts +2 -2
- package/dist/components/status-indicator/index.d.ts +2 -2
- package/dist/components/stepper/back.d.ts +71 -0
- package/dist/components/stepper/back.js +82 -0
- package/dist/components/stepper/back.js.map +1 -0
- package/dist/components/stepper/context.d.ts +49 -0
- package/dist/components/stepper/context.js +56 -0
- package/dist/components/stepper/context.js.map +1 -0
- package/dist/components/stepper/index.d.ts +22 -0
- package/dist/components/stepper/index.js +23 -0
- package/dist/components/stepper/list.d.ts +65 -0
- package/dist/components/stepper/list.js +121 -0
- package/dist/components/stepper/list.js.map +1 -0
- package/dist/components/stepper/next.d.ts +80 -0
- package/dist/components/stepper/next.js +91 -0
- package/dist/components/stepper/next.js.map +1 -0
- package/dist/components/stepper/panel.d.ts +66 -0
- package/dist/components/stepper/panel.js +77 -0
- package/dist/components/stepper/panel.js.map +1 -0
- package/dist/components/stepper/step.d.ts +49 -0
- package/dist/components/stepper/step.js +89 -0
- package/dist/components/stepper/step.js.map +1 -0
- package/dist/components/stepper/stepper.d.ts +130 -0
- package/dist/components/stepper/stepper.js +154 -0
- package/dist/components/stepper/stepper.js.map +1 -0
- package/dist/components/stepper/styles.module.css +126 -0
- package/dist/components/stepper/types.d.ts +205 -0
- package/dist/components/stepper/types.js +12 -0
- package/dist/components/stepper/use-stepper-state.d.ts +175 -0
- package/dist/components/stepper/use-stepper-state.js +225 -0
- package/dist/components/stepper/use-stepper-state.js.map +1 -0
- package/dist/components/switch/context.d.ts +4 -4
- package/dist/components/switch/index.d.ts +2 -2
- package/dist/components/table/body.d.ts +4 -3
- package/dist/components/table/body.js.map +1 -1
- package/dist/components/table/cell.d.ts +4 -3
- package/dist/components/table/cell.js.map +1 -1
- package/dist/components/table/context.d.ts +2 -2
- package/dist/components/table/features.d.ts +80 -0
- package/dist/components/table/features.js +61 -0
- package/dist/components/table/features.js.map +1 -0
- package/dist/components/table/header-cell.d.ts +4 -3
- package/dist/components/table/header-cell.js.map +1 -1
- package/dist/components/table/header.d.ts +4 -3
- package/dist/components/table/header.js.map +1 -1
- package/dist/components/table/index.d.ts +2 -2
- package/dist/components/table/index.js +40 -49
- package/dist/components/table/index.js.map +1 -1
- package/dist/components/table/row-ordering-feature.d.ts +88 -0
- package/dist/components/table/row-ordering-feature.js +115 -0
- package/dist/components/table/row-ordering-feature.js.map +1 -0
- package/dist/components/table/row.d.ts +4 -3
- package/dist/components/table/row.js.map +1 -1
- package/dist/components/table/types.d.ts +15 -13
- package/dist/components/tabs/context.d.ts +6 -6
- package/dist/components/tabs/index.d.ts +2 -2
- package/dist/components/tabs/list.d.ts +2 -2
- package/dist/components/tabs/panel.d.ts +2 -2
- package/dist/components/tabs/tab.d.ts +2 -2
- package/dist/components/text-area-field/context.d.ts +4 -4
- package/dist/components/text-area-field/index.d.ts +2 -2
- package/dist/components/text-field/context.d.ts +4 -4
- package/dist/components/text-field/index.d.ts +2 -2
- package/dist/components/time-field/index.d.ts +2 -2
- package/dist/components/tooltip/context.d.ts +2 -2
- package/dist/components/tooltip/index.d.ts +2 -2
- package/dist/components/tooltip/trigger.d.ts +2 -2
- package/dist/components/tree/context.d.ts +3 -3
- package/dist/components/tree/index.d.ts +2 -2
- package/dist/components/tree/item-actions.d.ts +2 -2
- package/dist/components/tree/item-content.d.ts +2 -2
- package/dist/components/tree/item-description.d.ts +2 -2
- package/dist/components/tree/item-label.d.ts +2 -2
- package/dist/components/tree/item-prefix-icon.d.ts +2 -2
- package/dist/components/tree/item.d.ts +2 -2
- package/dist/components/tree/lines.d.ts +2 -2
- package/dist/components/video/index.d.ts +2 -2
- package/dist/components/view-stack/context.d.ts +2 -2
- package/dist/components/view-stack/index.d.ts +2 -2
- package/dist/components/view-stack/trigger.d.ts +2 -2
- package/dist/components/view-stack/view.d.ts +2 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +11 -1
- package/dist/providers/portal.d.ts +2 -2
- package/dist/providers/theme-provider.d.ts +2 -2
- package/package.json +28 -12
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Bounds, Dimensions, Position } from "../types.js";
|
|
14
|
+
|
|
15
|
+
//#region src/components/floating-card/hooks/use-drag.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Clamps a position so the card stays fully inside its bounds.
|
|
18
|
+
*
|
|
19
|
+
* @param position - Desired top-left position.
|
|
20
|
+
* @param dimensions - Card size, used to keep the far edges inside.
|
|
21
|
+
* @param bounds - Box the card must remain within.
|
|
22
|
+
* @returns The clamped position.
|
|
23
|
+
*/
|
|
24
|
+
declare function constrainPosition(position: Position, dimensions: Dimensions, bounds: Bounds): Position;
|
|
25
|
+
type UseDragProps = {
|
|
26
|
+
/** Whether dragging is disabled, e.g. because the card is pinned. */
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
/** Current card position. */
|
|
29
|
+
position: Position;
|
|
30
|
+
/** Current card dimensions. */
|
|
31
|
+
dimensions: Dimensions;
|
|
32
|
+
/** Reads the bounding box once when the gesture starts. */
|
|
33
|
+
getBounds: () => Bounds;
|
|
34
|
+
/** Called with each new position during the drag. */
|
|
35
|
+
onPositionChange: (position: Position) => void;
|
|
36
|
+
/** Called once when the drag threshold is first crossed. */
|
|
37
|
+
onDragStart?: () => void;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Drags a card by a pointer gesture, keeping it inside its container.
|
|
41
|
+
*
|
|
42
|
+
* @param props - {@link UseDragProps}
|
|
43
|
+
* @returns A `handleStart` handler to attach to the card's drag surface.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a
|
|
47
|
+
* click on the header still reads as a click. Bounds are read once per gesture
|
|
48
|
+
* rather than per move to keep the drag off the layout path.
|
|
49
|
+
*/
|
|
50
|
+
declare function useDrag({
|
|
51
|
+
disabled,
|
|
52
|
+
position,
|
|
53
|
+
dimensions,
|
|
54
|
+
getBounds,
|
|
55
|
+
onPositionChange,
|
|
56
|
+
onDragStart
|
|
57
|
+
}: UseDragProps): {
|
|
58
|
+
handleStart: (event: PointerEvent, payload: void) => void;
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { UseDragProps, constrainPosition, useDrag };
|
|
62
|
+
//# sourceMappingURL=use-drag.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { DRAG_THRESHOLD } from "../constants.js";
|
|
15
|
+
import { useMouseInteraction } from "./use-mouse-interaction.js";
|
|
16
|
+
import { useRef } from "react";
|
|
17
|
+
import { clamp } from "radashi";
|
|
18
|
+
|
|
19
|
+
//#region src/components/floating-card/hooks/use-drag.ts
|
|
20
|
+
/** Elements that own their own pointer behavior and must never begin a drag. */
|
|
21
|
+
const INTERACTIVE_SELECTORS = [
|
|
22
|
+
"button",
|
|
23
|
+
"input",
|
|
24
|
+
"select",
|
|
25
|
+
"textarea",
|
|
26
|
+
"a",
|
|
27
|
+
"[role=\"button\"]",
|
|
28
|
+
"[role=\"link\"]",
|
|
29
|
+
"[contenteditable]"
|
|
30
|
+
].join(", ");
|
|
31
|
+
function isInteractiveElement(target) {
|
|
32
|
+
return target instanceof Element && target.closest(INTERACTIVE_SELECTORS) ? true : false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Clamps a position so the card stays fully inside its bounds.
|
|
36
|
+
*
|
|
37
|
+
* @param position - Desired top-left position.
|
|
38
|
+
* @param dimensions - Card size, used to keep the far edges inside.
|
|
39
|
+
* @param bounds - Box the card must remain within.
|
|
40
|
+
* @returns The clamped position.
|
|
41
|
+
*/
|
|
42
|
+
function constrainPosition(position, dimensions, bounds) {
|
|
43
|
+
const maxX = Math.max(bounds.left, bounds.right - dimensions.width);
|
|
44
|
+
const maxY = Math.max(bounds.top, bounds.bottom - dimensions.height);
|
|
45
|
+
return {
|
|
46
|
+
x: clamp(position.x, bounds.left, maxX),
|
|
47
|
+
y: clamp(position.y, bounds.top, maxY)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Drags a card by a pointer gesture, keeping it inside its container.
|
|
52
|
+
*
|
|
53
|
+
* @param props - {@link UseDragProps}
|
|
54
|
+
* @returns A `handleStart` handler to attach to the card's drag surface.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a
|
|
58
|
+
* click on the header still reads as a click. Bounds are read once per gesture
|
|
59
|
+
* rather than per move to keep the drag off the layout path.
|
|
60
|
+
*/
|
|
61
|
+
function useDrag({ disabled, position, dimensions, getBounds, onPositionChange, onDragStart }) {
|
|
62
|
+
const latest = useRef({
|
|
63
|
+
position,
|
|
64
|
+
dimensions,
|
|
65
|
+
disabled
|
|
66
|
+
});
|
|
67
|
+
latest.current = {
|
|
68
|
+
position,
|
|
69
|
+
dimensions,
|
|
70
|
+
disabled
|
|
71
|
+
};
|
|
72
|
+
const { handleStart } = useMouseInteraction({
|
|
73
|
+
shouldStart: (event) => !latest.current.disabled && event.button === 0 && !isInteractiveElement(event.target),
|
|
74
|
+
onStart: (event) => ({
|
|
75
|
+
isDragging: false,
|
|
76
|
+
pointerX: event.clientX,
|
|
77
|
+
pointerY: event.clientY,
|
|
78
|
+
origin: latest.current.position,
|
|
79
|
+
bounds: getBounds()
|
|
80
|
+
}),
|
|
81
|
+
onMove: (event, session) => {
|
|
82
|
+
const deltaX = event.clientX - session.pointerX;
|
|
83
|
+
const deltaY = event.clientY - session.pointerY;
|
|
84
|
+
if (!session.isDragging && Math.hypot(deltaX, deltaY) < DRAG_THRESHOLD) return;
|
|
85
|
+
if (!session.isDragging) {
|
|
86
|
+
session.isDragging = true;
|
|
87
|
+
onDragStart?.();
|
|
88
|
+
}
|
|
89
|
+
onPositionChange(constrainPosition({
|
|
90
|
+
x: session.origin.x + deltaX,
|
|
91
|
+
y: session.origin.y + deltaY
|
|
92
|
+
}, latest.current.dimensions, session.bounds));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return { handleStart };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
export { constrainPosition, useDrag };
|
|
100
|
+
//# sourceMappingURL=use-drag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-drag.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-drag.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { clamp } from 'radashi';\nimport { useRef } from 'react';\nimport { DRAG_THRESHOLD } from '../constants';\nimport { useMouseInteraction } from './use-mouse-interaction';\nimport type { Bounds, Dimensions, Position } from '../types';\n\n/** Elements that own their own pointer behavior and must never begin a drag. */\nconst INTERACTIVE_SELECTORS = [\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'a',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[contenteditable]',\n].join(', ');\n\nfunction isInteractiveElement(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest(INTERACTIVE_SELECTORS)\n ? true\n : false;\n}\n\n/**\n * Clamps a position so the card stays fully inside its bounds.\n *\n * @param position - Desired top-left position.\n * @param dimensions - Card size, used to keep the far edges inside.\n * @param bounds - Box the card must remain within.\n * @returns The clamped position.\n */\nexport function constrainPosition(\n position: Position,\n dimensions: Dimensions,\n bounds: Bounds,\n): Position {\n // A card wider than its bounds has no valid range, so the far edge is pinned\n // to the near one and the card rests against the top-left corner.\n const maxX = Math.max(bounds.left, bounds.right - dimensions.width);\n const maxY = Math.max(bounds.top, bounds.bottom - dimensions.height);\n\n return {\n x: clamp(position.x, bounds.left, maxX),\n y: clamp(position.y, bounds.top, maxY),\n };\n}\n\ntype DragSession = {\n isDragging: boolean;\n pointerX: number;\n pointerY: number;\n origin: Position;\n bounds: Bounds;\n};\n\nexport type UseDragProps = {\n /** Whether dragging is disabled, e.g. because the card is pinned. */\n disabled: boolean;\n /** Current card position. */\n position: Position;\n /** Current card dimensions. */\n dimensions: Dimensions;\n /** Reads the bounding box once when the gesture starts. */\n getBounds: () => Bounds;\n /** Called with each new position during the drag. */\n onPositionChange: (position: Position) => void;\n /** Called once when the drag threshold is first crossed. */\n onDragStart?: () => void;\n};\n\n/**\n * Drags a card by a pointer gesture, keeping it inside its container.\n *\n * @param props - {@link UseDragProps}\n * @returns A `handleStart` handler to attach to the card's drag surface.\n *\n * @remarks\n * A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a\n * click on the header still reads as a click. Bounds are read once per gesture\n * rather than per move to keep the drag off the layout path.\n */\nexport function useDrag({\n disabled,\n position,\n dimensions,\n getBounds,\n onPositionChange,\n onDragStart,\n}: UseDragProps) {\n // Read inside the session so a drag in progress always sees current values.\n const latest = useRef({ position, dimensions, disabled });\n latest.current = { position, dimensions, disabled };\n\n const { handleStart } = useMouseInteraction<DragSession>({\n shouldStart: (event) =>\n !latest.current.disabled &&\n event.button === 0 &&\n !isInteractiveElement(event.target),\n onStart: (event) => ({\n isDragging: false,\n pointerX: event.clientX,\n pointerY: event.clientY,\n origin: latest.current.position,\n bounds: getBounds(),\n }),\n onMove: (event, session) => {\n const deltaX = event.clientX - session.pointerX;\n const deltaY = event.clientY - session.pointerY;\n\n if (!session.isDragging && Math.hypot(deltaX, deltaY) < DRAG_THRESHOLD) {\n return;\n }\n\n if (!session.isDragging) {\n session.isDragging = true;\n onDragStart?.();\n }\n\n onPositionChange(\n constrainPosition(\n {\n x: session.origin.x + deltaX,\n y: session.origin.y + deltaY,\n },\n latest.current.dimensions,\n session.bounds,\n ),\n );\n },\n });\n\n return { handleStart };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,KAAK;AAEZ,SAAS,qBAAqB,QAAqC;AACjE,QAAO,kBAAkB,WAAW,OAAO,QAAQ,sBAAsB,GACrE,OACA;;;;;;;;;;AAWN,SAAgB,kBACd,UACA,YACA,QACU;CAGV,MAAM,OAAO,KAAK,IAAI,OAAO,MAAM,OAAO,QAAQ,WAAW,MAAM;CACnE,MAAM,OAAO,KAAK,IAAI,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO;AAEpE,QAAO;EACL,GAAG,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK;EACvC,GAAG,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK;EACvC;;;;;;;;;;;;;AAqCH,SAAgB,QAAQ,EACtB,UACA,UACA,YACA,WACA,kBACA,eACe;CAEf,MAAM,SAAS,OAAO;EAAE;EAAU;EAAY;EAAU,CAAC;AACzD,QAAO,UAAU;EAAE;EAAU;EAAY;EAAU;CAEnD,MAAM,EAAE,gBAAgB,oBAAiC;EACvD,cAAc,UACZ,CAAC,OAAO,QAAQ,YAChB,MAAM,WAAW,KACjB,CAAC,qBAAqB,MAAM,OAAO;EACrC,UAAU,WAAW;GACnB,YAAY;GACZ,UAAU,MAAM;GAChB,UAAU,MAAM;GAChB,QAAQ,OAAO,QAAQ;GACvB,QAAQ,WAAW;GACpB;EACD,SAAS,OAAO,YAAY;GAC1B,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,SAAS,MAAM,UAAU,QAAQ;AAEvC,OAAI,CAAC,QAAQ,cAAc,KAAK,MAAM,QAAQ,OAAO,GAAG,eACtD;AAGF,OAAI,CAAC,QAAQ,YAAY;AACvB,YAAQ,aAAa;AACrB,mBAAe;;AAGjB,oBACE,kBACE;IACE,GAAG,QAAQ,OAAO,IAAI;IACtB,GAAG,QAAQ,OAAO,IAAI;IACvB,EACD,OAAO,QAAQ,YACf,QAAQ,OACT,CACF;;EAEJ,CAAC;AAEF,QAAO,EAAE,aAAa"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/components/floating-card/hooks/use-mouse-interaction.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for a pointer-driven interaction session.
|
|
4
|
+
*
|
|
5
|
+
* @template Session - Mutable state carried through a single interaction.
|
|
6
|
+
*/
|
|
7
|
+
type MouseInteractionConfig<Session, Payload = void> = {
|
|
8
|
+
/**
|
|
9
|
+
* Called on pointerdown. Return the session state, or null to abort.
|
|
10
|
+
*
|
|
11
|
+
* @remarks `payload` carries whatever the caller passed to `handleStart`,
|
|
12
|
+
* which lets one element's handler describe what it started -- a resize
|
|
13
|
+
* handle naming its direction, for instance.
|
|
14
|
+
*/
|
|
15
|
+
onStart: (event: PointerEvent, payload: Payload) => Session | null;
|
|
16
|
+
/**
|
|
17
|
+
* Called on each pointermove while a session is active.
|
|
18
|
+
*
|
|
19
|
+
* @remarks The session object persists across the whole gesture and may be
|
|
20
|
+
* mutated in place to carry state between moves.
|
|
21
|
+
*/
|
|
22
|
+
onMove: (event: PointerEvent, session: Session) => void;
|
|
23
|
+
/** Optional. Called on pointerup or pointercancel, ending the session. */
|
|
24
|
+
onEnd?: (event: PointerEvent, session: Session) => void;
|
|
25
|
+
/** Optional guard run before onStart; return false to ignore the event. */
|
|
26
|
+
shouldStart?: (event: PointerEvent) => boolean;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Runs a pointer-driven interaction (drag, resize) against document-level
|
|
30
|
+
* listeners so the gesture keeps tracking when the pointer leaves the element.
|
|
31
|
+
*
|
|
32
|
+
* @param config - Session lifecycle callbacks.
|
|
33
|
+
* @returns A `handleStart` handler to attach to the element that begins the gesture.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* Listeners are registered only for the duration of a session and torn down
|
|
37
|
+
* with an AbortController, which also covers unmounting mid-gesture.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const { handleStart } = useMouseInteraction({
|
|
42
|
+
* onStart: (event) => ({ startX: event.clientX }),
|
|
43
|
+
* onMove: (event, session) => move(event.clientX - session.startX),
|
|
44
|
+
* onEnd: () => commit(),
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function useMouseInteraction<Session, Payload = void>({
|
|
49
|
+
onStart,
|
|
50
|
+
onMove,
|
|
51
|
+
onEnd,
|
|
52
|
+
shouldStart
|
|
53
|
+
}: MouseInteractionConfig<Session, Payload>): {
|
|
54
|
+
handleStart: (event: PointerEvent, payload: Payload) => void;
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
export { MouseInteractionConfig, useMouseInteraction };
|
|
58
|
+
//# sourceMappingURL=use-mouse-interaction.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
15
|
+
|
|
16
|
+
//#region src/components/floating-card/hooks/use-mouse-interaction.ts
|
|
17
|
+
/**
|
|
18
|
+
* Runs a pointer-driven interaction (drag, resize) against document-level
|
|
19
|
+
* listeners so the gesture keeps tracking when the pointer leaves the element.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Session lifecycle callbacks.
|
|
22
|
+
* @returns A `handleStart` handler to attach to the element that begins the gesture.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Listeners are registered only for the duration of a session and torn down
|
|
26
|
+
* with an AbortController, which also covers unmounting mid-gesture.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const { handleStart } = useMouseInteraction({
|
|
31
|
+
* onStart: (event) => ({ startX: event.clientX }),
|
|
32
|
+
* onMove: (event, session) => move(event.clientX - session.startX),
|
|
33
|
+
* onEnd: () => commit(),
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function useMouseInteraction({ onStart, onMove, onEnd, shouldStart }) {
|
|
38
|
+
const sessionRef = useRef(null);
|
|
39
|
+
const abortRef = useRef(null);
|
|
40
|
+
const handlers = useRef({
|
|
41
|
+
onStart,
|
|
42
|
+
onMove,
|
|
43
|
+
onEnd,
|
|
44
|
+
shouldStart
|
|
45
|
+
});
|
|
46
|
+
handlers.current = {
|
|
47
|
+
onStart,
|
|
48
|
+
onMove,
|
|
49
|
+
onEnd,
|
|
50
|
+
shouldStart
|
|
51
|
+
};
|
|
52
|
+
const endSession = useCallback(() => {
|
|
53
|
+
sessionRef.current = null;
|
|
54
|
+
abortRef.current?.abort();
|
|
55
|
+
abortRef.current = null;
|
|
56
|
+
}, []);
|
|
57
|
+
const handleStart = useCallback((event, payload) => {
|
|
58
|
+
if (handlers.current.shouldStart?.(event) === false) return;
|
|
59
|
+
const session = handlers.current.onStart(event, payload);
|
|
60
|
+
if (session === null) return;
|
|
61
|
+
abortRef.current?.abort();
|
|
62
|
+
sessionRef.current = session;
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
abortRef.current = controller;
|
|
66
|
+
const handleMove = (moveEvent) => {
|
|
67
|
+
if (sessionRef.current === null) return;
|
|
68
|
+
handlers.current.onMove(moveEvent, sessionRef.current);
|
|
69
|
+
};
|
|
70
|
+
const handleEnd = (endEvent) => {
|
|
71
|
+
if (sessionRef.current === null) return;
|
|
72
|
+
handlers.current.onEnd?.(endEvent, sessionRef.current);
|
|
73
|
+
endSession();
|
|
74
|
+
};
|
|
75
|
+
const options = { signal: controller.signal };
|
|
76
|
+
document.addEventListener("pointermove", handleMove, options);
|
|
77
|
+
document.addEventListener("pointerup", handleEnd, options);
|
|
78
|
+
document.addEventListener("pointercancel", handleEnd, options);
|
|
79
|
+
}, [endSession]);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
return () => {
|
|
82
|
+
abortRef.current?.abort();
|
|
83
|
+
abortRef.current = null;
|
|
84
|
+
};
|
|
85
|
+
}, []);
|
|
86
|
+
return { handleStart };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { useMouseInteraction };
|
|
91
|
+
//# sourceMappingURL=use-mouse-interaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mouse-interaction.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-mouse-interaction.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\n/**\n * Configuration for a pointer-driven interaction session.\n *\n * @template Session - Mutable state carried through a single interaction.\n */\nexport type MouseInteractionConfig<Session, Payload = void> = {\n /**\n * Called on pointerdown. Return the session state, or null to abort.\n *\n * @remarks `payload` carries whatever the caller passed to `handleStart`,\n * which lets one element's handler describe what it started -- a resize\n * handle naming its direction, for instance.\n */\n onStart: (event: PointerEvent, payload: Payload) => Session | null;\n /**\n * Called on each pointermove while a session is active.\n *\n * @remarks The session object persists across the whole gesture and may be\n * mutated in place to carry state between moves.\n */\n onMove: (event: PointerEvent, session: Session) => void;\n /** Optional. Called on pointerup or pointercancel, ending the session. */\n onEnd?: (event: PointerEvent, session: Session) => void;\n /** Optional guard run before onStart; return false to ignore the event. */\n shouldStart?: (event: PointerEvent) => boolean;\n};\n\n/**\n * Runs a pointer-driven interaction (drag, resize) against document-level\n * listeners so the gesture keeps tracking when the pointer leaves the element.\n *\n * @param config - Session lifecycle callbacks.\n * @returns A `handleStart` handler to attach to the element that begins the gesture.\n *\n * @remarks\n * Listeners are registered only for the duration of a session and torn down\n * with an AbortController, which also covers unmounting mid-gesture.\n *\n * @example\n * ```ts\n * const { handleStart } = useMouseInteraction({\n * onStart: (event) => ({ startX: event.clientX }),\n * onMove: (event, session) => move(event.clientX - session.startX),\n * onEnd: () => commit(),\n * });\n * ```\n */\nexport function useMouseInteraction<Session, Payload = void>({\n onStart,\n onMove,\n onEnd,\n shouldStart,\n}: MouseInteractionConfig<Session, Payload>) {\n const sessionRef = useRef<Session | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n // Callbacks are read from refs so a session started with one render's\n // handlers keeps working after a re-render without re-binding listeners.\n const handlers = useRef({ onStart, onMove, onEnd, shouldStart });\n handlers.current = { onStart, onMove, onEnd, shouldStart };\n\n const endSession = useCallback(() => {\n sessionRef.current = null;\n abortRef.current?.abort();\n abortRef.current = null;\n }, []);\n\n const handleStart = useCallback(\n (event: PointerEvent, payload: Payload) => {\n if (handlers.current.shouldStart?.(event) === false) {\n return;\n }\n\n const session = handlers.current.onStart(event, payload);\n\n if (session === null) {\n return;\n }\n\n // A second press before the first releases -- a lost pointerup, or a\n // resize handle pressed mid-drag -- would otherwise strand the previous\n // controller's listeners, leaving two sessions driving the same card.\n abortRef.current?.abort();\n\n sessionRef.current = session;\n event.preventDefault();\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n const handleMove = (moveEvent: PointerEvent) => {\n if (sessionRef.current === null) {\n return;\n }\n\n handlers.current.onMove(moveEvent, sessionRef.current);\n };\n\n const handleEnd = (endEvent: PointerEvent) => {\n if (sessionRef.current === null) {\n return;\n }\n\n handlers.current.onEnd?.(endEvent, sessionRef.current);\n endSession();\n };\n\n const options = { signal: controller.signal };\n\n document.addEventListener('pointermove', handleMove, options);\n document.addEventListener('pointerup', handleEnd, options);\n document.addEventListener('pointercancel', handleEnd, options);\n },\n [endSession],\n );\n\n useEffect(() => {\n return () => {\n abortRef.current?.abort();\n abortRef.current = null;\n };\n }, []);\n\n return { handleStart };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,oBAA6C,EAC3D,SACA,QACA,OACA,eAC2C;CAC3C,MAAM,aAAa,OAAuB,KAAK;CAC/C,MAAM,WAAW,OAA+B,KAAK;CAIrD,MAAM,WAAW,OAAO;EAAE;EAAS;EAAQ;EAAO;EAAa,CAAC;AAChE,UAAS,UAAU;EAAE;EAAS;EAAQ;EAAO;EAAa;CAE1D,MAAM,aAAa,kBAAkB;AACnC,aAAW,UAAU;AACrB,WAAS,SAAS,OAAO;AACzB,WAAS,UAAU;IAClB,EAAE,CAAC;CAEN,MAAM,cAAc,aACjB,OAAqB,YAAqB;AACzC,MAAI,SAAS,QAAQ,cAAc,MAAM,KAAK,MAC5C;EAGF,MAAM,UAAU,SAAS,QAAQ,QAAQ,OAAO,QAAQ;AAExD,MAAI,YAAY,KACd;AAMF,WAAS,SAAS,OAAO;AAEzB,aAAW,UAAU;AACrB,QAAM,gBAAgB;EAEtB,MAAM,aAAa,IAAI,iBAAiB;AACxC,WAAS,UAAU;EAEnB,MAAM,cAAc,cAA4B;AAC9C,OAAI,WAAW,YAAY,KACzB;AAGF,YAAS,QAAQ,OAAO,WAAW,WAAW,QAAQ;;EAGxD,MAAM,aAAa,aAA2B;AAC5C,OAAI,WAAW,YAAY,KACzB;AAGF,YAAS,QAAQ,QAAQ,UAAU,WAAW,QAAQ;AACtD,eAAY;;EAGd,MAAM,UAAU,EAAE,QAAQ,WAAW,QAAQ;AAE7C,WAAS,iBAAiB,eAAe,YAAY,QAAQ;AAC7D,WAAS,iBAAiB,aAAa,WAAW,QAAQ;AAC1D,WAAS,iBAAiB,iBAAiB,WAAW,QAAQ;IAEhE,CAAC,WAAW,CACb;AAED,iBAAgB;AACd,eAAa;AACX,YAAS,SAAS,OAAO;AACzB,YAAS,UAAU;;IAEpB,EAAE,CAAC;AAEN,QAAO,EAAE,aAAa"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Bounds, Dimensions, Position, ResizeHandle } from "../types.js";
|
|
14
|
+
|
|
15
|
+
//#region src/components/floating-card/hooks/use-resize.d.ts
|
|
16
|
+
type UseResizeProps = {
|
|
17
|
+
/** Whether resizing is disabled, e.g. because the card is pinned. */
|
|
18
|
+
disabled: boolean;
|
|
19
|
+
/** Current card position. */
|
|
20
|
+
position: Position;
|
|
21
|
+
/** Current card dimensions. */
|
|
22
|
+
dimensions: Dimensions;
|
|
23
|
+
/** Reads the bounding box once when the gesture starts. */
|
|
24
|
+
getBounds: () => Bounds;
|
|
25
|
+
/** Called with the new geometry during the resize. */
|
|
26
|
+
onResize: (dimensions: Dimensions, position: Position) => void;
|
|
27
|
+
/** Called once when the gesture begins. */
|
|
28
|
+
onResizeStart?: () => void;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Resizes a card from any of its eight edges and corners.
|
|
32
|
+
*
|
|
33
|
+
* @param props - {@link UseResizeProps}
|
|
34
|
+
* @returns `getHandleProps`, which builds the pointer handler for one handle.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* North and west handles move the card's origin as well as its size so the
|
|
38
|
+
* opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}
|
|
39
|
+
* and to the container, so a card can never be resized outside its bounds or
|
|
40
|
+
* collapsed to nothing.
|
|
41
|
+
*/
|
|
42
|
+
declare function useResize({
|
|
43
|
+
disabled,
|
|
44
|
+
position,
|
|
45
|
+
dimensions,
|
|
46
|
+
getBounds,
|
|
47
|
+
onResize,
|
|
48
|
+
onResizeStart
|
|
49
|
+
}: UseResizeProps): {
|
|
50
|
+
getHandleProps: (handle: ResizeHandle) => {
|
|
51
|
+
onPointerDown: (event: React.PointerEvent) => void;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { UseResizeProps, useResize };
|
|
56
|
+
//# sourceMappingURL=use-resize.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { MIN_DIMENSIONS } from "../constants.js";
|
|
15
|
+
import { useMouseInteraction } from "./use-mouse-interaction.js";
|
|
16
|
+
import { useCallback, useRef } from "react";
|
|
17
|
+
import { clamp } from "radashi";
|
|
18
|
+
|
|
19
|
+
//#region src/components/floating-card/hooks/use-resize.ts
|
|
20
|
+
/**
|
|
21
|
+
* Resizes a card from any of its eight edges and corners.
|
|
22
|
+
*
|
|
23
|
+
* @param props - {@link UseResizeProps}
|
|
24
|
+
* @returns `getHandleProps`, which builds the pointer handler for one handle.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* North and west handles move the card's origin as well as its size so the
|
|
28
|
+
* opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}
|
|
29
|
+
* and to the container, so a card can never be resized outside its bounds or
|
|
30
|
+
* collapsed to nothing.
|
|
31
|
+
*/
|
|
32
|
+
function useResize({ disabled, position, dimensions, getBounds, onResize, onResizeStart }) {
|
|
33
|
+
const latest = useRef({
|
|
34
|
+
position,
|
|
35
|
+
dimensions,
|
|
36
|
+
disabled
|
|
37
|
+
});
|
|
38
|
+
latest.current = {
|
|
39
|
+
position,
|
|
40
|
+
dimensions,
|
|
41
|
+
disabled
|
|
42
|
+
};
|
|
43
|
+
const { handleStart } = useMouseInteraction({
|
|
44
|
+
shouldStart: (event) => !latest.current.disabled && event.button === 0,
|
|
45
|
+
onStart: (event, handle) => {
|
|
46
|
+
onResizeStart?.();
|
|
47
|
+
return {
|
|
48
|
+
pointerX: event.clientX,
|
|
49
|
+
pointerY: event.clientY,
|
|
50
|
+
origin: latest.current.position,
|
|
51
|
+
size: latest.current.dimensions,
|
|
52
|
+
handle,
|
|
53
|
+
bounds: getBounds()
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
onMove: (event, session) => {
|
|
57
|
+
const deltaX = event.clientX - session.pointerX;
|
|
58
|
+
const deltaY = event.clientY - session.pointerY;
|
|
59
|
+
const { handle, origin, size, bounds } = session;
|
|
60
|
+
let { x, y } = origin;
|
|
61
|
+
let { width, height } = size;
|
|
62
|
+
if (handle.includes("e")) {
|
|
63
|
+
const limit = Math.max(bounds.right - origin.x, size.width);
|
|
64
|
+
width = Math.min(size.width + deltaX, limit);
|
|
65
|
+
}
|
|
66
|
+
if (handle.includes("s")) {
|
|
67
|
+
const limit = Math.max(bounds.bottom - origin.y, size.height);
|
|
68
|
+
height = Math.min(size.height + deltaY, limit);
|
|
69
|
+
}
|
|
70
|
+
if (handle.includes("w")) {
|
|
71
|
+
const right = origin.x + size.width;
|
|
72
|
+
const limit = Math.min(bounds.left, origin.x);
|
|
73
|
+
x = clamp(origin.x + deltaX, limit, right - MIN_DIMENSIONS.width);
|
|
74
|
+
width = right - x;
|
|
75
|
+
}
|
|
76
|
+
if (handle.includes("n")) {
|
|
77
|
+
const bottom = origin.y + size.height;
|
|
78
|
+
const limit = Math.min(bounds.top, origin.y);
|
|
79
|
+
y = clamp(origin.y + deltaY, limit, bottom - MIN_DIMENSIONS.height);
|
|
80
|
+
height = bottom - y;
|
|
81
|
+
}
|
|
82
|
+
onResize({
|
|
83
|
+
width: Math.max(width, MIN_DIMENSIONS.width),
|
|
84
|
+
height: Math.max(height, MIN_DIMENSIONS.height)
|
|
85
|
+
}, {
|
|
86
|
+
x,
|
|
87
|
+
y
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return { getHandleProps: useCallback((handle) => ({ onPointerDown: (event) => {
|
|
92
|
+
handleStart(event.nativeEvent, handle);
|
|
93
|
+
} }), [handleStart]) };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { useResize };
|
|
98
|
+
//# sourceMappingURL=use-resize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-resize.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-resize.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { clamp } from 'radashi';\nimport { useCallback, useRef } from 'react';\nimport { MIN_DIMENSIONS } from '../constants';\nimport { useMouseInteraction } from './use-mouse-interaction';\nimport type { Bounds, Dimensions, Position, ResizeHandle } from '../types';\n\ntype ResizeSession = {\n pointerX: number;\n pointerY: number;\n origin: Position;\n size: Dimensions;\n handle: ResizeHandle;\n bounds: Bounds;\n};\n\nexport type UseResizeProps = {\n /** Whether resizing is disabled, e.g. because the card is pinned. */\n disabled: boolean;\n /** Current card position. */\n position: Position;\n /** Current card dimensions. */\n dimensions: Dimensions;\n /** Reads the bounding box once when the gesture starts. */\n getBounds: () => Bounds;\n /** Called with the new geometry during the resize. */\n onResize: (dimensions: Dimensions, position: Position) => void;\n /** Called once when the gesture begins. */\n onResizeStart?: () => void;\n};\n\n/**\n * Resizes a card from any of its eight edges and corners.\n *\n * @param props - {@link UseResizeProps}\n * @returns `getHandleProps`, which builds the pointer handler for one handle.\n *\n * @remarks\n * North and west handles move the card's origin as well as its size so the\n * opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}\n * and to the container, so a card can never be resized outside its bounds or\n * collapsed to nothing.\n */\nexport function useResize({\n disabled,\n position,\n dimensions,\n getBounds,\n onResize,\n onResizeStart,\n}: UseResizeProps) {\n const latest = useRef({ position, dimensions, disabled });\n latest.current = { position, dimensions, disabled };\n\n const { handleStart } = useMouseInteraction<ResizeSession, ResizeHandle>({\n shouldStart: (event) => !latest.current.disabled && event.button === 0,\n onStart: (event, handle) => {\n onResizeStart?.();\n\n return {\n pointerX: event.clientX,\n pointerY: event.clientY,\n origin: latest.current.position,\n size: latest.current.dimensions,\n handle,\n bounds: getBounds(),\n };\n },\n onMove: (event, session) => {\n const deltaX = event.clientX - session.pointerX;\n const deltaY = event.clientY - session.pointerY;\n const { handle, origin, size, bounds } = session;\n\n let { x, y } = origin;\n let { width, height } = size;\n\n // A card that already extends past its bounds must still be resizable, so\n // the limit never falls below the size the gesture started at -- otherwise\n // the first pointermove would snap it inward.\n if (handle.includes('e')) {\n const limit = Math.max(bounds.right - origin.x, size.width);\n\n width = Math.min(size.width + deltaX, limit);\n }\n\n if (handle.includes('s')) {\n const limit = Math.max(bounds.bottom - origin.y, size.height);\n\n height = Math.min(size.height + deltaY, limit);\n }\n\n if (handle.includes('w')) {\n // Clamping x first keeps the right edge fixed while honouring bounds.\n const right = origin.x + size.width;\n const limit = Math.min(bounds.left, origin.x);\n\n x = clamp(origin.x + deltaX, limit, right - MIN_DIMENSIONS.width);\n width = right - x;\n }\n\n if (handle.includes('n')) {\n const bottom = origin.y + size.height;\n const limit = Math.min(bounds.top, origin.y);\n\n y = clamp(origin.y + deltaY, limit, bottom - MIN_DIMENSIONS.height);\n height = bottom - y;\n }\n\n onResize(\n {\n width: Math.max(width, MIN_DIMENSIONS.width),\n height: Math.max(height, MIN_DIMENSIONS.height),\n },\n { x, y },\n );\n },\n });\n\n const getHandleProps = useCallback(\n (handle: ResizeHandle) => ({\n onPointerDown: (event: React.PointerEvent) => {\n handleStart(event.nativeEvent, handle);\n },\n }),\n [handleStart],\n );\n\n return { getHandleProps };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,UAAU,EACxB,UACA,UACA,YACA,WACA,UACA,iBACiB;CACjB,MAAM,SAAS,OAAO;EAAE;EAAU;EAAY;EAAU,CAAC;AACzD,QAAO,UAAU;EAAE;EAAU;EAAY;EAAU;CAEnD,MAAM,EAAE,gBAAgB,oBAAiD;EACvE,cAAc,UAAU,CAAC,OAAO,QAAQ,YAAY,MAAM,WAAW;EACrE,UAAU,OAAO,WAAW;AAC1B,oBAAiB;AAEjB,UAAO;IACL,UAAU,MAAM;IAChB,UAAU,MAAM;IAChB,QAAQ,OAAO,QAAQ;IACvB,MAAM,OAAO,QAAQ;IACrB;IACA,QAAQ,WAAW;IACpB;;EAEH,SAAS,OAAO,YAAY;GAC1B,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,EAAE,QAAQ,QAAQ,MAAM,WAAW;GAEzC,IAAI,EAAE,GAAG,MAAM;GACf,IAAI,EAAE,OAAO,WAAW;AAKxB,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,QAAQ,KAAK,IAAI,OAAO,QAAQ,OAAO,GAAG,KAAK,MAAM;AAE3D,YAAQ,KAAK,IAAI,KAAK,QAAQ,QAAQ,MAAM;;AAG9C,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,QAAQ,KAAK,IAAI,OAAO,SAAS,OAAO,GAAG,KAAK,OAAO;AAE7D,aAAS,KAAK,IAAI,KAAK,SAAS,QAAQ,MAAM;;AAGhD,OAAI,OAAO,SAAS,IAAI,EAAE;IAExB,MAAM,QAAQ,OAAO,IAAI,KAAK;IAC9B,MAAM,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,EAAE;AAE7C,QAAI,MAAM,OAAO,IAAI,QAAQ,OAAO,QAAQ,eAAe,MAAM;AACjE,YAAQ,QAAQ;;AAGlB,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,SAAS,OAAO,IAAI,KAAK;IAC/B,MAAM,QAAQ,KAAK,IAAI,OAAO,KAAK,OAAO,EAAE;AAE5C,QAAI,MAAM,OAAO,IAAI,QAAQ,OAAO,SAAS,eAAe,OAAO;AACnE,aAAS,SAAS;;AAGpB,YACE;IACE,OAAO,KAAK,IAAI,OAAO,eAAe,MAAM;IAC5C,QAAQ,KAAK,IAAI,QAAQ,eAAe,OAAO;IAChD,EACD;IAAE;IAAG;IAAG,CACT;;EAEJ,CAAC;AAWF,QAAO,EAAE,gBATc,aACpB,YAA0B,EACzB,gBAAgB,UAA8B;AAC5C,cAAY,MAAM,aAAa,OAAO;IAEzC,GACD,CAAC,YAAY,CACd,EAEwB"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { FloatingCardProps } from "./types.js";
|
|
14
|
-
import * as
|
|
14
|
+
import * as react16 from "react";
|
|
15
15
|
import { PropsWithChildren } from "react";
|
|
16
16
|
|
|
17
17
|
//#region src/components/floating-card/index.d.ts
|
|
@@ -33,6 +33,10 @@ import { PropsWithChildren } from "react";
|
|
|
33
33
|
* @remarks
|
|
34
34
|
* - Requires `FloatingCardProvider` as an ancestor.
|
|
35
35
|
* - The floating card is only rendered if a valid DOM reference exists for the given `id`.
|
|
36
|
+
* - `initialDimensions` and `initialPosition` are applied each time the card
|
|
37
|
+
* opens. While it stays open, later changes to them are ignored so a user's
|
|
38
|
+
* own drag or resize is never overridden; closing and reopening starts the
|
|
39
|
+
* card from those values again.
|
|
36
40
|
*
|
|
37
41
|
* @example
|
|
38
42
|
* ```tsx
|
|
@@ -64,7 +68,7 @@ declare function FloatingCard({
|
|
|
64
68
|
isOpen,
|
|
65
69
|
initialDimensions,
|
|
66
70
|
initialPosition
|
|
67
|
-
}: PropsWithChildren<FloatingCardProps>):
|
|
71
|
+
}: PropsWithChildren<FloatingCardProps>): react16.ReactPortal | null;
|
|
68
72
|
//#endregion
|
|
69
73
|
export { FloatingCard };
|
|
70
74
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -11,15 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { DEFAULT_DIMENSIONS, DEFAULT_POSITION } from "./constants.js";
|
|
15
|
+
import { useFloatingCard, useFloatingCardRegistry } from "./context.js";
|
|
15
16
|
import { useEffect } from "react";
|
|
16
17
|
import { createPortal } from "react-dom";
|
|
17
18
|
|
|
18
19
|
//#region src/components/floating-card/index.tsx
|
|
19
|
-
const defaultDimensions = {
|
|
20
|
-
width: 300,
|
|
21
|
-
height: 400
|
|
22
|
-
};
|
|
23
20
|
/**
|
|
24
21
|
* Renders its children into a floating card using React portals.
|
|
25
22
|
*
|
|
@@ -37,6 +34,10 @@ const defaultDimensions = {
|
|
|
37
34
|
* @remarks
|
|
38
35
|
* - Requires `FloatingCardProvider` as an ancestor.
|
|
39
36
|
* - The floating card is only rendered if a valid DOM reference exists for the given `id`.
|
|
37
|
+
* - `initialDimensions` and `initialPosition` are applied each time the card
|
|
38
|
+
* opens. While it stays open, later changes to them are ignored so a user's
|
|
39
|
+
* own drag or resize is never overridden; closing and reopening starts the
|
|
40
|
+
* card from those values again.
|
|
40
41
|
*
|
|
41
42
|
* @example
|
|
42
43
|
* ```tsx
|
|
@@ -62,29 +63,22 @@ const defaultDimensions = {
|
|
|
62
63
|
* ```
|
|
63
64
|
*/
|
|
64
65
|
function FloatingCard({ id, children, title, isOpen = true, initialDimensions, initialPosition }) {
|
|
65
|
-
const { cards,
|
|
66
|
-
const {
|
|
67
|
-
const {
|
|
66
|
+
const { cards, closeCard } = useFloatingCard();
|
|
67
|
+
const { openCard } = useFloatingCardRegistry();
|
|
68
|
+
const { width, height } = initialDimensions ?? DEFAULT_DIMENSIONS;
|
|
69
|
+
const { x, y } = initialPosition ?? DEFAULT_POSITION;
|
|
68
70
|
useEffect(() => {
|
|
69
|
-
if (!floatingCardApi) return;
|
|
70
71
|
if (!isOpen) {
|
|
71
|
-
|
|
72
|
+
closeCard(id);
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
height,
|
|
82
|
-
x,
|
|
83
|
-
y
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
panel.group.locked = "no-drop-target";
|
|
87
|
-
}
|
|
75
|
+
openCard(id, title, {
|
|
76
|
+
x,
|
|
77
|
+
y
|
|
78
|
+
}, {
|
|
79
|
+
width,
|
|
80
|
+
height
|
|
81
|
+
});
|
|
88
82
|
}, [
|
|
89
83
|
id,
|
|
90
84
|
title,
|
|
@@ -93,16 +87,14 @@ function FloatingCard({ id, children, title, isOpen = true, initialDimensions, i
|
|
|
93
87
|
height,
|
|
94
88
|
x,
|
|
95
89
|
y,
|
|
96
|
-
|
|
90
|
+
openCard,
|
|
91
|
+
closeCard
|
|
97
92
|
]);
|
|
98
93
|
useEffect(() => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
floatingCardApi,
|
|
104
|
-
id
|
|
105
|
-
]);
|
|
94
|
+
return () => {
|
|
95
|
+
closeCard(id);
|
|
96
|
+
};
|
|
97
|
+
}, [id, closeCard]);
|
|
106
98
|
return isOpen && cards[id] ? createPortal(children, cards[id]) : null;
|
|
107
99
|
}
|
|
108
100
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/floating-card/index.tsx"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { type PropsWithChildren, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/floating-card/index.tsx"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { type PropsWithChildren, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { DEFAULT_DIMENSIONS, DEFAULT_POSITION } from './constants';\nimport { useFloatingCard, useFloatingCardRegistry } from './context';\nimport type { FloatingCardProps } from './types';\n\n/**\n * Renders its children into a floating card using React portals.\n *\n * The `FloatingCard` component registers itself with the floating card engine on mount\n * and renders its children into the corresponding DOM node via a portal.\n *\n * @param id - Unique identifier for the floating card.\n * @param title - Optional title displayed in the floating card header.\n * @param isOpen - Whether the floating card is rendered. Defaults to `true`.\n * @param initialDimensions - Initial width and height of the floating card. Defaults to `{ width: 300, height: 400 }`.\n * @param initialPosition - Initial x and y coordinates of the floating card.\n * @param children - React children to render inside the floating card.\n * @returns The floating card component (portaled content) or null.\n *\n * @remarks\n * - Requires `FloatingCardProvider` as an ancestor.\n * - The floating card is only rendered if a valid DOM reference exists for the given `id`.\n * - `initialDimensions` and `initialPosition` are applied each time the card\n * opens. While it stays open, later changes to them are ignored so a user's\n * own drag or resize is never overridden; closing and reopening starts the\n * card from those values again.\n *\n * @example\n * ```tsx\n * import { uuid } from '@accelint/core/utility/uuid';\n *\n * const cardId = uuid();\n * const [isOpen, setIsOpen] = useState(true);\n *\n * <FloatingCardProvider>\n * <FloatingCard\n * id={cardId}\n * title=\"Settings Panel\"\n * isOpen={isOpen}\n * initialDimensions={{ width: 400, height: 500 }}\n * >\n * <SettingsForm />\n * </FloatingCard>\n *\n * <button onClick={() => setIsOpen(!isOpen)}>\n * Toggle Panel\n * </button>\n * </FloatingCardProvider>\n * ```\n */\nexport function FloatingCard({\n id,\n children,\n title,\n isOpen = true,\n initialDimensions,\n initialPosition,\n}: PropsWithChildren<FloatingCardProps>) {\n const { cards, closeCard } = useFloatingCard();\n const { openCard } = useFloatingCardRegistry();\n\n const { width, height } = initialDimensions ?? DEFAULT_DIMENSIONS;\n const { x, y } = initialPosition ?? DEFAULT_POSITION;\n\n useEffect(() => {\n if (!isOpen) {\n closeCard(id);\n\n return;\n }\n\n openCard(id, title, { x, y }, { width, height });\n }, [id, title, isOpen, width, height, x, y, openCard, closeCard]);\n\n // Unregister on unmount so a card removed from the tree leaves no panel behind.\n useEffect(() => {\n return () => {\n closeCard(id);\n };\n }, [id, closeCard]);\n\n return isOpen && cards[id] ? createPortal(children, cards[id]) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,SAAgB,aAAa,EAC3B,IACA,UACA,OACA,SAAS,MACT,mBACA,mBACuC;CACvC,MAAM,EAAE,OAAO,cAAc,iBAAiB;CAC9C,MAAM,EAAE,aAAa,yBAAyB;CAE9C,MAAM,EAAE,OAAO,WAAW,qBAAqB;CAC/C,MAAM,EAAE,GAAG,MAAM,mBAAmB;AAEpC,iBAAgB;AACd,MAAI,CAAC,QAAQ;AACX,aAAU,GAAG;AAEb;;AAGF,WAAS,IAAI,OAAO;GAAE;GAAG;GAAG,EAAE;GAAE;GAAO;GAAQ,CAAC;IAC/C;EAAC;EAAI;EAAO;EAAQ;EAAO;EAAQ;EAAG;EAAG;EAAU;EAAU,CAAC;AAGjE,iBAAgB;AACd,eAAa;AACX,aAAU,GAAG;;IAEd,CAAC,IAAI,UAAU,CAAC;AAEnB,QAAO,UAAU,MAAM,MAAM,aAAa,UAAU,MAAM,IAAI,GAAG"}
|