@xh/hoist 72.0.0-SNAPSHOT.1736347917533 → 72.0.0-SNAPSHOT.1736808794610

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## v72.0.0-SNAPSHOT - unreleased
4
4
 
5
+ ### ⚙️ Typescript API Adjustments
6
+
7
+ * Improved signature of `HoistBase.markPersist`.
8
+
5
9
  ## v71.0.0 - 2025-01-08
6
10
 
7
11
  ### 💥 Breaking Changes (upgrade difficulty: 🟠 MEDIUM - Hoist core update, import adjustments)
@@ -134,7 +134,7 @@ export declare abstract class HoistBase {
134
134
  * @param options - options governing the persistence of this object. These will be applied
135
135
  * on top of any default persistWith options defined on the instance itself.
136
136
  */
137
- markPersist(property: keyof this & string, options?: PersistOptions): void;
137
+ markPersist<P extends keyof this & string>(property: P, options?: PersistOptions): void;
138
138
  /** @returns true if this instance has been destroyed. */
139
139
  get isDestroyed(): boolean;
140
140
  /**
package/core/HoistBase.ts CHANGED
@@ -256,7 +256,7 @@ export abstract class HoistBase {
256
256
  * @param options - options governing the persistence of this object. These will be applied
257
257
  * on top of any default persistWith options defined on the instance itself.
258
258
  */
259
- markPersist(property: keyof this & string, options: PersistOptions = {}) {
259
+ markPersist<P extends keyof this & string>(property: P, options: PersistOptions = {}) {
260
260
  // Read from and attach to Provider, failing gently
261
261
  PersistenceProvider.create({
262
262
  persistOptions: {
@@ -35,7 +35,6 @@ export const [DateEditor, dateEditor] = hoistCmp.withFactory<DateEditorProps>({
35
35
  ...props,
36
36
  inputProps: {
37
37
  rightElement: null,
38
-
39
38
  enablePicker: !!portalContainer,
40
39
  showPickerOnFocus: !!portalContainer,
41
40
  portalContainer,
@@ -5,35 +5,46 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- .xh-date-input {
9
- // Style input in picker-only mode
10
- &--picker-only {
11
- input {
12
- color: var(--xh-input-text-color) !important;
13
- background-color: var(--xh-input-bg) !important;
14
- cursor: pointer !important;
15
- }
16
-
17
- .bp5-input-group.bp5-disabled {
18
- cursor: pointer !important;
19
- }
8
+ .xh-date-input__wrapper {
9
+ .bp5-input-action {
10
+ height: 100%;
20
11
  }
21
12
 
22
- // Style picker icon in input-only mode
23
- &__picker-icon--disabled:hover {
24
- background-color: transparent !important;
25
- cursor: not-allowed;
13
+ .bp5-input-group .xh-icon {
14
+ position: relative;
15
+ margin: 0 !important;
26
16
  }
27
17
 
28
- // Style buttons when disabled
29
- &.xh-input-disabled:not(.xh-date-input--picker-only) button:hover {
30
- background-color: transparent !important;
31
- cursor: not-allowed;
32
- }
18
+ .xh-date-input {
19
+ // Style input in picker-only mode
20
+ &--picker-only {
21
+ input {
22
+ color: var(--xh-input-text-color) !important;
23
+ background-color: var(--xh-input-bg) !important;
24
+ cursor: pointer !important;
25
+ }
26
+
27
+ .bp5-input-group.bp5-disabled {
28
+ cursor: pointer !important;
29
+ }
30
+ }
33
31
 
34
- // Prevent browser from capturing click events when input is disabled due to use of
35
- // enableTextInput: false prop. See https://github.com/xh/hoist-react/issues/3460
36
- input[disabled] {
37
- pointer-events: none;
32
+ // Style picker icon in input-only mode
33
+ &__picker-icon--disabled:hover {
34
+ background-color: transparent !important;
35
+ cursor: not-allowed;
36
+ }
37
+
38
+ // Style buttons when disabled
39
+ &.xh-input-disabled:not(.xh-date-input--picker-only) button:hover {
40
+ background-color: transparent !important;
41
+ cursor: not-allowed;
42
+ }
43
+
44
+ // Prevent browser from capturing click events when input is disabled due to use of
45
+ // enableTextInput: false prop. See https://github.com/xh/hoist-react/issues/3460
46
+ input[disabled] {
47
+ pointer-events: none;
48
+ }
38
49
  }
39
50
  }
@@ -8,9 +8,9 @@ import {PopperBoundary, PopperModifierOverrides} from '@blueprintjs/core';
8
8
  import {TimePickerProps} from '@blueprintjs/datetime';
9
9
  import {ReactDayPickerSingleProps} from '@blueprintjs/datetime2/src/common/reactDayPickerProps';
10
10
  import {HoistInputModel, HoistInputProps, useHoistInputModel} from '@xh/hoist/cmp/input';
11
- import {div} from '@xh/hoist/cmp/layout';
11
+ import {div, hbox} from '@xh/hoist/cmp/layout';
12
12
  import {hoistCmp, HoistProps, HSide, LayoutProps, Some} from '@xh/hoist/core';
13
- import {button, buttonGroup} from '@xh/hoist/desktop/cmp/button';
13
+ import {button} from '@xh/hoist/desktop/cmp/button';
14
14
  import {textInput, TextInputModel} from '@xh/hoist/desktop/cmp/input';
15
15
  import '@xh/hoist/desktop/register';
16
16
  import {fmtDate} from '@xh/hoist/format';
@@ -19,10 +19,10 @@ import {datePicker as bpDatePicker, popover, Position} from '@xh/hoist/kit/bluep
19
19
  import {bindable, makeObservable} from '@xh/hoist/mobx';
20
20
  import {wait} from '@xh/hoist/promise';
21
21
  import {isLocalDate, LocalDate} from '@xh/hoist/utils/datetime';
22
- import {consumeEvent, getTestId, warnIf, withDefault} from '@xh/hoist/utils/js';
22
+ import {consumeEvent, getTestId, withDefault} from '@xh/hoist/utils/js';
23
23
  import {getLayoutProps} from '@xh/hoist/utils/react';
24
24
  import classNames from 'classnames';
25
- import {assign, castArray, clone, trim} from 'lodash';
25
+ import {assign, castArray, clone, isEmpty, trim} from 'lodash';
26
26
  import moment from 'moment';
27
27
  import {createRef, ReactElement, ReactNode} from 'react';
28
28
  import './DateInput.scss';
@@ -375,44 +375,11 @@ class DateInputModel extends HoistInputModel {
375
375
 
376
376
  const cmp = hoistCmp.factory<DateInputProps & {model: DateInputModel}>(
377
377
  ({model, className, ...props}, ref) => {
378
- warnIf(
379
- (props.enableClear || props.enablePicker) && props.rightElement,
380
- 'Cannot specify enableClear or enablePicker along with custom rightElement - built-in clear/picker button will not be shown.'
381
- );
382
-
383
378
  const enablePicker = props.enablePicker ?? true,
384
379
  enableTextInput = props.enableTextInput ?? true,
385
- enableClear = props.enableClear ?? false,
386
380
  disabled = props.disabled ?? false,
387
- isClearable = model.internalValue !== null,
388
381
  isOpen = enablePicker && model.popoverOpen && !disabled;
389
382
 
390
- const buttons = buttonGroup({
391
- padding: 0,
392
- items: [
393
- button({
394
- className: 'xh-date-input__clear-icon',
395
- omit: !enableClear || !isClearable || disabled,
396
- icon: Icon.cross(),
397
- tabIndex: -1,
398
- onClick: model.onClearBtnClick,
399
- testId: getTestId(props, 'clear')
400
- }),
401
- button({
402
- className: classNames(
403
- 'xh-date-input__picker-icon',
404
- enablePicker ? null : 'xh-date-input__picker-icon--disabled'
405
- ),
406
- icon: Icon.calendar(),
407
- tabIndex: enableTextInput || disabled ? -1 : undefined,
408
- ref: model.buttonRef,
409
- onClick: enablePicker && !disabled ? model.onOpenPopoverClick : null,
410
- testId: getTestId(props, 'picker')
411
- })
412
- ]
413
- });
414
- const rightElement = withDefault(props.rightElement, buttons);
415
-
416
383
  let {minDate, maxDate, initialMonth, renderValue} = model;
417
384
 
418
385
  // If app has set an out-of-range date, we render it -- these bounds govern *manual* entry
@@ -475,9 +442,15 @@ const cmp = hoistCmp.factory<DateInputProps & {model: DateInputModel}>(
475
442
  onCommit: model.onInputCommit,
476
443
  onChange: model.onInputChange,
477
444
  onKeyDown: model.onInputKeyDown,
478
- rightElement: rightElement as ReactElement,
479
445
  disabled: disabled || !enableTextInput,
480
446
  leftIcon: props.leftIcon,
447
+ rightElement: rightIcons({
448
+ model,
449
+ ...props,
450
+ disabled,
451
+ enableTextInput,
452
+ enablePicker
453
+ }),
481
454
  tabIndex: props.tabIndex,
482
455
  placeholder: props.placeholder,
483
456
  textAlign: props.textAlign,
@@ -498,3 +471,44 @@ const cmp = hoistCmp.factory<DateInputProps & {model: DateInputModel}>(
498
471
  });
499
472
  }
500
473
  );
474
+
475
+ const rightIcons = hoistCmp.factory<DateInputModel>({
476
+ render({model, disabled, enableTextInput, enablePicker, ...props}) {
477
+ const buttonLayoutProps = {padding: 0, margin: 0, height: '100%'},
478
+ enableClear = props.enableClear ?? false,
479
+ isClearable = model.internalValue !== null,
480
+ items = [];
481
+
482
+ // 1) First potential icon is clear button
483
+ if (enableClear && isClearable && !disabled) {
484
+ items.push(
485
+ button({
486
+ className: 'xh-date-input__clear-icon',
487
+ icon: Icon.cross(),
488
+ tabIndex: -1,
489
+ onClick: model.onClearBtnClick,
490
+ testId: getTestId(props, 'clear'),
491
+ ...buttonLayoutProps
492
+ })
493
+ );
494
+ }
495
+
496
+ // 2) Second potential icon is app-specified, or default calendar icon. Set prop to null to hide.
497
+ const rightElement = withDefault(
498
+ props.rightElement,
499
+ button({
500
+ className: 'xh-date-input__picker-icon',
501
+ icon: Icon.calendar(),
502
+ tabIndex: enableTextInput || disabled ? -1 : undefined,
503
+ onClick: enablePicker && !disabled ? model.onOpenPopoverClick : null,
504
+ testId: getTestId(props, 'picker'),
505
+ disabled,
506
+ ref: model.buttonRef,
507
+ ...buttonLayoutProps
508
+ })
509
+ );
510
+ if (rightElement) items.push(rightElement);
511
+
512
+ return hbox({height: '100%', paddingRight: 3, items, omit: isEmpty(items)});
513
+ }
514
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "72.0.0-SNAPSHOT.1736347917533",
3
+ "version": "72.0.0-SNAPSHOT.1736808794610",
4
4
  "description": "Hoist add-on for building and deploying React Applications.",
5
5
  "repository": "github:xh/hoist-react",
6
6
  "homepage": "https://xh.io",