Skip to content

Commit 8ff33cf

Browse files
Form: add indication for Smart Past feature (DevExpress#30917)
1 parent dc2f6f7 commit 8ff33cf

File tree

6 files changed

+685
-3
lines changed

6 files changed

+685
-3
lines changed

packages/devextreme-scss/scss/widgets/base/_form.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,13 @@
166166
unicode-bidi: embed;
167167
}
168168
}
169+
170+
.dx-form {
171+
position: relative;
172+
}
173+
174+
.dx-form-loadpanel-wrapper {
175+
.dx-loadpanel-content {
176+
padding: 0;
177+
}
178+
}

packages/devextreme/js/__internal/ui/form/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ export const GROUP_COL_COUNT_CLASS = 'dx-group-colcount-';
2121
export const GROUP_COL_COUNT_ATTR = 'group-col-count';
2222
export const FORM_VALIDATION_SUMMARY = 'dx-form-validation-summary';
2323
export const FORM_UNDERLINED_CLASS = 'dx-form-styling-mode-underlined';
24+
export const FORM_LOAD_PANEL_CLASS = 'dx-form-loadpanel';
25+
export const FORM_LOAD_PANEL_WRAPPER_CLASS = 'dx-form-loadpanel-wrapper';
2426

2527
export const SIMPLE_ITEM_TYPE = 'simple';
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import type { dxElementWrapper } from '@js/core/renderer';
2+
import $ from '@js/core/renderer';
3+
import {
4+
FORM_LOAD_PANEL_CLASS,
5+
FORM_LOAD_PANEL_WRAPPER_CLASS,
6+
} from '@ts/ui/form/constants';
7+
import LoadIndicator, { AnimationType } from '@ts/ui/load_indicator';
8+
import type { LoadPanelProperties } from '@ts/ui/load_panel';
9+
import type LoadPanel from '@ts/ui/load_panel';
10+
11+
const FORM_LOAD_INDICATOR_SIZE = 120;
12+
13+
interface FormLoadPanelDependencies {
14+
$container: dxElementWrapper;
15+
onLoadPanelCreate: ($element: dxElementWrapper, options: LoadPanelProperties) => LoadPanel;
16+
}
17+
18+
export class FormLoadPanel {
19+
private readonly _dependencies: FormLoadPanelDependencies;
20+
21+
private _loadPanel?: LoadPanel;
22+
23+
constructor(dependencies: FormLoadPanelDependencies) {
24+
this._dependencies = dependencies;
25+
}
26+
27+
show(): void {
28+
this._ensureLoadPanel();
29+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
30+
this._loadPanel?.show();
31+
}
32+
33+
hide(): void {
34+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
35+
this._loadPanel?.hide();
36+
}
37+
38+
dispose(): void {
39+
if (!this._loadPanel) {
40+
return;
41+
}
42+
43+
this._loadPanel.dispose();
44+
this._loadPanel.$element().remove();
45+
this._loadPanel = undefined;
46+
}
47+
48+
get instance(): LoadPanel | undefined {
49+
return this._loadPanel;
50+
}
51+
52+
option(name: string): unknown {
53+
return this._loadPanel?.option(name);
54+
}
55+
56+
private _ensureLoadPanel(): void {
57+
if (this._loadPanel) {
58+
return;
59+
}
60+
61+
const $loadPanel = $('<div>')
62+
.addClass(FORM_LOAD_PANEL_CLASS)
63+
.appendTo(this._dependencies.$container);
64+
65+
this._loadPanel = this._dependencies.onLoadPanelCreate($loadPanel, {
66+
position: {
67+
of: this._dependencies.$container.get(0),
68+
},
69+
visible: false,
70+
showIndicator: true,
71+
showPane: false,
72+
shading: false,
73+
hideOnOutsideClick: false,
74+
hideOnParentScroll: false,
75+
deferRendering: false,
76+
disabled: false,
77+
message: '',
78+
wrapperAttr: {
79+
class: FORM_LOAD_PANEL_WRAPPER_CLASS,
80+
},
81+
});
82+
83+
this._configureLoadIndicator();
84+
}
85+
86+
private _configureLoadIndicator(): void {
87+
const $loadIndicator = this._loadPanel?._$indicator;
88+
89+
if ($loadIndicator?.length) {
90+
const loadIndicator = LoadIndicator.getInstance($loadIndicator.get(0));
91+
92+
loadIndicator.option({
93+
animationType: AnimationType.Sparkle,
94+
width: FORM_LOAD_INDICATOR_SIZE,
95+
height: FORM_LOAD_INDICATOR_SIZE,
96+
});
97+
}
98+
}
99+
}

packages/devextreme/js/__internal/ui/form/form.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import type {
7575
import FormItemsRunTimeInfo from '@ts/ui/form/form.items_runtime_info';
7676
import type { ExtendedLayoutManagerProperties, LayoutManagerProperties } from '@ts/ui/form/form.layout_manager';
7777
import LayoutManager from '@ts/ui/form/form.layout_manager';
78+
import { FormLoadPanel } from '@ts/ui/form/form.load_panel';
7879
import {
7980
concatPaths,
8081
convertToLayoutManagerOptions,
@@ -87,6 +88,8 @@ import {
8788
isFullPathContainsTabs,
8889
tryGetTabPath,
8990
} from '@ts/ui/form/form.utils';
91+
import type { LoadPanelProperties } from '@ts/ui/load_panel';
92+
import LoadPanel from '@ts/ui/load_panel';
9093
import ValidationEngine from '@ts/ui/m_validation_engine';
9194
import ValidationSummary from '@ts/ui/m_validation_summary';
9295
import type { ScreenSizeQualifier } from '@ts/ui/responsive_box';
@@ -157,6 +160,8 @@ class Form extends Widget<FormProperties> {
157160

158161
_$validationSummary?: dxElementWrapper;
159162

163+
_loadPanel?: FormLoadPanel;
164+
160165
_init(): void {
161166
super._init();
162167

@@ -1653,8 +1658,33 @@ class Form extends Widget<FormProperties> {
16531658
}
16541659
}
16551660

1661+
private _ensureLoadPanel(): void {
1662+
if (!this._loadPanel) {
1663+
this._loadPanel = new FormLoadPanel({
1664+
$container: this.$element(),
1665+
onLoadPanelCreate: (
1666+
$element: dxElementWrapper,
1667+
options: LoadPanelProperties,
1668+
): LoadPanel => this._createComponent($element, LoadPanel, options),
1669+
});
1670+
}
1671+
}
1672+
1673+
private _showLoadPanel(): void {
1674+
this._ensureLoadPanel();
1675+
this.option('disabled', true);
1676+
this._loadPanel?.show();
1677+
}
1678+
1679+
private _hideLoadPanel(): void {
1680+
this._loadPanel?.hide();
1681+
this.option('disabled', false);
1682+
}
1683+
16561684
_dispose(): void {
16571685
this._clearAutoColCountChangedTimeout();
1686+
this._processCommandCompletion();
1687+
this._loadPanel?.dispose();
16581688
ValidationEngine.removeGroup(this._getValidationGroup());
16591689
super._dispose();
16601690
}
@@ -1793,6 +1823,7 @@ class Form extends Widget<FormProperties> {
17931823
this._abort?.();
17941824
this._abort = undefined;
17951825
this._currentAICommand = undefined;
1826+
this._hideLoadPanel();
17961827
}
17971828

17981829
private _processAIIntegrationUpdate(): void {
@@ -1827,9 +1858,11 @@ class Form extends Widget<FormProperties> {
18271858
this._updateFieldValue(name, value);
18281859
});
18291860
this.endUpdate();
1861+
this._hideLoadPanel();
18301862
this._processCommandCompletion();
18311863
},
18321864
onError: (): void => {
1865+
this._hideLoadPanel();
18331866
this._processCommandCompletion();
18341867
},
18351868
};
@@ -1840,14 +1873,20 @@ class Form extends Widget<FormProperties> {
18401873
this._processCommandCompletion();
18411874
}
18421875

1876+
const smartPasteText = text ?? await navigator.clipboard?.readText();
1877+
1878+
if (isDefined(smartPasteText)) {
1879+
this._showLoadPanel();
1880+
}
1881+
18431882
const dataItems = this._itemsRunTimeInfo.getItemsForDataExtraction();
18441883
const fields = dataItems.map((item) => ({
18451884
name: item.dataField,
18461885
format: getItemFormatInfo(item),
18471886
instruction: item.aiOptions?.instruction,
18481887
}));
18491888
const smartPasteParams = {
1850-
text: text ?? await navigator.clipboard.readText(),
1889+
text: smartPasteText,
18511890
fields,
18521891
};
18531892
const smartPasteCallbacks = this._getSmartPasteCommandCallbacks();

0 commit comments

Comments
 (0)