first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
@@ -0,0 +1,60 @@
import * as React from 'react';
import type { IDraggableZoneProps, ICoordinates } from './DraggableZone.types';
import type { JSXElement } from '@fluentui/utilities';
export interface IDraggableZoneState {
isDragging: boolean;
position: ICoordinates;
lastPosition?: ICoordinates;
}
export declare class DraggableZone extends React.Component<IDraggableZoneProps, IDraggableZoneState> {
static contextType: React.Context<import("@fluentui/react-window-provider").WindowProviderProps>;
context: any;
private _touchId?;
private _currentEventType;
private _events;
constructor(props: IDraggableZoneProps);
componentDidUpdate(prevProps: IDraggableZoneProps): void;
componentWillUnmount(): void;
render(): JSXElement;
private _onMouseDown;
private _onMouseUp;
private _onTouchStart;
private _onTouchEnd;
private _onDragStart;
private _onDrag;
private _onDragStop;
/**
* Get the control position based off the event that fired
* @param event - The event to get offsets from
*/
private _getControlPosition;
/**
* Get the active touch point that we have saved from the event's TouchList
* @param event - The event used to get the TouchList for the active touch point
*/
private _getActiveTouch;
/**
* Get the initial touch identifier associated with the given event
* @param event - The event that contains the TouchList
*/
private _getTouchId;
/**
* Returns if an element (or any of the element's parents) match the given selector
*/
private _matchesSelector;
/**
* Attempts to find the Touch that matches the identifier we stored in dragStart
* @param touchList The TouchList to look for the stored identifier from dragStart
*/
private _findTouchInTouchList;
/**
* Create DragData based off of the last known position and the new position passed in
* @param position The new position as part of the drag
*/
private _createDragDataFromPosition;
/**
* Creates an updated DragData based off the current position and given baseDragData
* @param baseDragData The base DragData (from _createDragDataFromPosition) used to calculate the updated positions
*/
private _createUpdatedDragData;
}
@@ -0,0 +1,278 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DraggableZone = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var DraggableZone_styles_1 = require("./DraggableZone.styles");
var Utilities_1 = require("../../Utilities");
var react_window_provider_1 = require("@fluentui/react-window-provider");
var dom_1 = require("../dom");
var eventMapping = {
touch: {
start: 'touchstart',
move: 'touchmove',
stop: 'touchend',
},
mouse: {
start: 'mousedown',
move: 'mousemove',
stop: 'mouseup',
},
};
var DraggableZone = /** @class */ (function (_super) {
tslib_1.__extends(DraggableZone, _super);
function DraggableZone(props) {
var _this = _super.call(this, props) || this;
_this._currentEventType = eventMapping.mouse;
_this._events = [];
_this._onMouseDown = function (event) {
var onMouseDown = React.Children.only(_this.props.children).props.onMouseDown;
if (onMouseDown) {
onMouseDown(event);
}
_this._currentEventType = eventMapping.mouse;
return _this._onDragStart(event);
};
_this._onMouseUp = function (event) {
var onMouseUp = React.Children.only(_this.props.children).props.onMouseUp;
if (onMouseUp) {
onMouseUp(event);
}
_this._currentEventType = eventMapping.mouse;
return _this._onDragStop(event);
};
_this._onTouchStart = function (event) {
var onTouchStart = React.Children.only(_this.props.children).props.onTouchStart;
if (onTouchStart) {
onTouchStart(event);
}
_this._currentEventType = eventMapping.touch;
return _this._onDragStart(event);
};
_this._onTouchEnd = function (event) {
var onTouchEnd = React.Children.only(_this.props.children).props.onTouchEnd;
if (onTouchEnd) {
onTouchEnd(event);
}
_this._currentEventType = eventMapping.touch;
_this._onDragStop(event);
};
_this._onDragStart = function (event) {
// Only handle left click for dragging
if (typeof event.button === 'number' && event.button !== 0) {
return false;
}
// If the target doesn't match the handleSelector OR
// if the target does match the preventDragSelector, bail out
if ((_this.props.handleSelector && !_this._matchesSelector(event.target, _this.props.handleSelector)) ||
(_this.props.preventDragSelector &&
_this._matchesSelector(event.target, _this.props.preventDragSelector))) {
return;
}
// Remember the touch identifier if this is a touch event so we can
// distinguish between individual touches in multitouch scenarios
// by remembering which touch point we were given
_this._touchId = _this._getTouchId(event);
var position = _this._getControlPosition(event);
if (position === undefined) {
return;
}
var dragData = _this._createDragDataFromPosition(position);
_this.props.onStart && _this.props.onStart(event, dragData);
_this.setState({
isDragging: true,
lastPosition: position,
});
// hook up the appropriate mouse/touch events to the body to ensure
// smooth dragging
var doc = (0, dom_1.getDocumentEx)(_this.context);
_this._events = [
(0, Utilities_1.on)(doc.body, _this._currentEventType.move, _this._onDrag, true /* use capture phase */),
(0, Utilities_1.on)(doc.body, _this._currentEventType.stop, _this._onDragStop, true /* use capture phase */),
];
};
_this._onDrag = function (event) {
// Prevent scrolling on mobile devices
if (event.type === 'touchmove') {
event.preventDefault();
}
var position = _this._getControlPosition(event);
if (!position) {
return;
}
// create the updated drag data from the position data
var updatedData = _this._createUpdatedDragData(_this._createDragDataFromPosition(position));
var updatedPosition = updatedData.position;
_this.props.onDragChange && _this.props.onDragChange(event, updatedData);
_this.setState({
position: updatedPosition,
lastPosition: position,
});
};
_this._onDragStop = function (event) {
if (!_this.state.isDragging) {
return;
}
var position = _this._getControlPosition(event);
if (!position) {
return;
}
var baseDragData = _this._createDragDataFromPosition(position);
// Set dragging to false and reset the lastPosition
_this.setState({
isDragging: false,
lastPosition: undefined,
});
_this.props.onStop && _this.props.onStop(event, baseDragData);
if (_this.props.position) {
_this.setState({
position: _this.props.position,
});
}
// Remove event handlers
_this._events.forEach(function (dispose) { return dispose(); });
};
_this.state = {
isDragging: false,
position: _this.props.position || { x: 0, y: 0 },
lastPosition: undefined,
};
return _this;
}
DraggableZone.prototype.componentDidUpdate = function (prevProps) {
if (this.props.position && (!prevProps.position || this.props.position !== prevProps.position)) {
this.setState({ position: this.props.position });
}
};
DraggableZone.prototype.componentWillUnmount = function () {
this._events.forEach(function (dispose) { return dispose(); });
};
DraggableZone.prototype.render = function () {
var child = React.Children.only(this.props.children);
var props = child.props;
var position = this.props.position;
var _a = this.state, statePosition = _a.position, isDragging = _a.isDragging;
var x = statePosition.x;
var y = statePosition.y;
if (position && !isDragging) {
x = position.x;
y = position.y;
}
return React.cloneElement(child, {
style: tslib_1.__assign(tslib_1.__assign({}, props.style), { transform: "translate(".concat(x, "px, ").concat(y, "px)") }),
className: (0, DraggableZone_styles_1.getClassNames)(props.className, this.state.isDragging).root,
onMouseDown: this._onMouseDown,
onMouseUp: this._onMouseUp,
onTouchStart: this._onTouchStart,
onTouchEnd: this._onTouchEnd,
});
};
/**
* Get the control position based off the event that fired
* @param event - The event to get offsets from
*/
DraggableZone.prototype._getControlPosition = function (event) {
var touchObj = this._getActiveTouch(event);
// did we get the right touch?
if (this._touchId !== undefined && !touchObj) {
return undefined;
}
var eventToGetOffset = touchObj || event;
return {
x: eventToGetOffset.clientX,
y: eventToGetOffset.clientY,
};
};
/**
* Get the active touch point that we have saved from the event's TouchList
* @param event - The event used to get the TouchList for the active touch point
*/
DraggableZone.prototype._getActiveTouch = function (event) {
return ((event.targetTouches && this._findTouchInTouchList(event.targetTouches)) ||
(event.changedTouches && this._findTouchInTouchList(event.changedTouches)));
};
/**
* Get the initial touch identifier associated with the given event
* @param event - The event that contains the TouchList
*/
DraggableZone.prototype._getTouchId = function (event) {
var touch = (event.targetTouches && event.targetTouches[0]) || (event.changedTouches && event.changedTouches[0]);
if (touch) {
return touch.identifier;
}
};
/**
* Returns if an element (or any of the element's parents) match the given selector
*/
DraggableZone.prototype._matchesSelector = function (element, selector) {
var _a;
if (!element || element === ((_a = (0, dom_1.getDocumentEx)(this.context)) === null || _a === void 0 ? void 0 : _a.body)) {
return false;
}
var matchesSelectorFn =
// eslint-disable-next-line @typescript-eslint/no-deprecated
element.matches || element.webkitMatchesSelector || element.msMatchesSelector; /* for IE */
if (!matchesSelectorFn) {
return false;
}
return matchesSelectorFn.call(element, selector) || this._matchesSelector(element.parentElement, selector);
};
/**
* Attempts to find the Touch that matches the identifier we stored in dragStart
* @param touchList The TouchList to look for the stored identifier from dragStart
*/
DraggableZone.prototype._findTouchInTouchList = function (touchList) {
if (this._touchId === undefined) {
return;
}
for (var i = 0; i < touchList.length; i++) {
if (touchList[i].identifier === this._touchId) {
return touchList[i];
}
}
return undefined;
};
/**
* Create DragData based off of the last known position and the new position passed in
* @param position The new position as part of the drag
*/
DraggableZone.prototype._createDragDataFromPosition = function (position) {
var lastPosition = this.state.lastPosition;
// If we have no lastPosition, use the given position
// for last position
if (lastPosition === undefined) {
return {
delta: { x: 0, y: 0 },
lastPosition: position,
position: position,
};
}
return {
delta: {
x: position.x - lastPosition.x,
y: position.y - lastPosition.y,
},
lastPosition: lastPosition,
position: position,
};
};
/**
* Creates an updated DragData based off the current position and given baseDragData
* @param baseDragData The base DragData (from _createDragDataFromPosition) used to calculate the updated positions
*/
DraggableZone.prototype._createUpdatedDragData = function (baseDragData) {
var position = this.state.position;
return {
position: {
x: position.x + baseDragData.delta.x,
y: position.y + baseDragData.delta.y,
},
delta: baseDragData.delta,
lastPosition: position,
};
};
DraggableZone.contextType = react_window_provider_1.WindowContext;
return DraggableZone;
}(React.Component));
exports.DraggableZone = DraggableZone;
//# sourceMappingURL=DraggableZone.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
export interface IDraggableZoneStyles {
root: string;
}
export declare const getClassNames: (className: string, isDragging: boolean) => IDraggableZoneStyles;
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getClassNames = void 0;
var Utilities_1 = require("../../Utilities");
var Styling_1 = require("../../Styling");
exports.getClassNames = (0, Utilities_1.memoizeFunction)(function (className, isDragging) {
return {
root: (0, Styling_1.mergeStyles)(className, isDragging && {
touchAction: 'none',
selectors: {
'& *': {
userSelect: 'none',
},
},
}),
};
});
//# sourceMappingURL=DraggableZone.styles.js.map
@@ -0,0 +1 @@
{"version":3,"file":"DraggableZone.styles.js","sourceRoot":"../src/","sources":["utilities/DraggableZone/DraggableZone.styles.ts"],"names":[],"mappings":";;;AAAA,6CAAkD;AAClD,yCAA4C;AAM/B,QAAA,aAAa,GAAG,IAAA,2BAAe,EAAC,UAAC,SAAiB,EAAE,UAAmB;IAClF,OAAO;QACL,IAAI,EAAE,IAAA,qBAAW,EACf,SAAS,EACT,UAAU,IAAI;YACZ,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE;gBACT,KAAK,EAAE;oBACL,UAAU,EAAE,MAAM;iBACnB;aACF;SACF,CACF;KACF,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { memoizeFunction } from '../../Utilities';\nimport { mergeStyles } from '../../Styling';\n\nexport interface IDraggableZoneStyles {\n root: string;\n}\n\nexport const getClassNames = memoizeFunction((className: string, isDragging: boolean): IDraggableZoneStyles => {\n return {\n root: mergeStyles(\n className,\n isDragging && {\n touchAction: 'none',\n selectors: {\n '& *': {\n userSelect: 'none',\n },\n },\n },\n ),\n };\n});\n"]}
@@ -0,0 +1,39 @@
import * as React from 'react';
export interface IDragData {
position: ICoordinates;
lastPosition?: ICoordinates;
delta: ICoordinates;
}
export interface ICoordinates {
x: number;
y: number;
}
export interface IDraggableZoneProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Specifies a selector to be used as the handle that initiates drag
*/
handleSelector?: string;
/**
* Specifies a selector to be used to prevent drag initialization.
* For example, if you do not want buttons inside of your handleSelector
* to have the cursor change to move or to allow users to select from buttons,
* you could pass button here (the close button in the header of a dialog is a concrete example)
*/
preventDragSelector?: string;
/**
* the X and Y coordinates to use as an offest to position the draggable content
*/
position?: ICoordinates;
/**
* Callback for when dragging starts
*/
onStart?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;
/**
* Callback for when the drag changes, while dragging
*/
onDragChange?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;
/**
* Callback for when dragging stops
*/
onStop?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;
}
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=DraggableZone.types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"DraggableZone.types.js","sourceRoot":"../src/","sources":["utilities/DraggableZone/DraggableZone.types.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\n\nexport interface IDragData {\n position: ICoordinates;\n lastPosition?: ICoordinates;\n delta: ICoordinates;\n}\n\nexport interface ICoordinates {\n x: number;\n y: number;\n}\n\nexport interface IDraggableZoneProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Specifies a selector to be used as the handle that initiates drag\n */\n handleSelector?: string;\n\n /**\n * Specifies a selector to be used to prevent drag initialization.\n * For example, if you do not want buttons inside of your handleSelector\n * to have the cursor change to move or to allow users to select from buttons,\n * you could pass button here (the close button in the header of a dialog is a concrete example)\n */\n preventDragSelector?: string;\n\n /**\n * the X and Y coordinates to use as an offest to position the draggable content\n */\n position?: ICoordinates;\n\n /**\n * Callback for when dragging starts\n */\n onStart?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;\n\n /**\n * Callback for when the drag changes, while dragging\n */\n onDragChange?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;\n\n /**\n * Callback for when dragging stops\n */\n onStop?: (event: React.MouseEvent<HTMLElement> & React.TouchEvent<HTMLElement>, dragData: IDragData) => void;\n}\n"]}
@@ -0,0 +1,3 @@
export * from './DraggableZone';
export * from './DraggableZone.types';
export * from './DraggableZone.styles';
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./DraggableZone"), exports);
tslib_1.__exportStar(require("./DraggableZone.types"), exports);
tslib_1.__exportStar(require("./DraggableZone.styles"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["utilities/DraggableZone/index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC;AAChC,gEAAsC;AACtC,iEAAuC","sourcesContent":["export * from './DraggableZone';\nexport * from './DraggableZone.types';\nexport * from './DraggableZone.styles';\n"]}