@xh/hoist 71.0.0-SNAPSHOT.1735332336875 → 71.0.0-SNAPSHOT.1735335976186

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
@@ -40,6 +40,11 @@
40
40
  * Added workaround for problematic use of SASS-syntax-in-CSS shipped by `react-dates`. This began
41
41
  throwing "This function isn't allowed in plain CSS" with latest version of sass/sass-loader.
42
42
 
43
+ ### ⚙️ Typescript API Adjustments
44
+
45
+ * Improved accuracy of `IconProps` interface, with use of the `IconName` and `IconPrefix` types
46
+ provided by FontAwesome.
47
+
43
48
  ## v70.0.0 - 2024-11-15
44
49
 
45
50
  ### 💥 Breaking Changes (upgrade difficulty: 🟢 LOW - changes to advanced persistence APIs)
@@ -11,7 +11,7 @@ import {fragment, p} from '@xh/hoist/cmp/layout';
11
11
  import {HoistModel, Intent, LoadSpec, managed, PlainObject, XH} from '@xh/hoist/core';
12
12
  import {dateIs, required} from '@xh/hoist/data';
13
13
  import {action, bindable, computed, makeObservable, observable} from '@xh/hoist/mobx';
14
- import {AlertBannerSpec} from '@xh/hoist/svc';
14
+ import {AlertBannerIconName, AlertBannerSpec} from '@xh/hoist/svc';
15
15
  import {isEqual, isMatch, sortBy, without} from 'lodash';
16
16
 
17
17
  export class AlertBannerModel extends HoistModel {
@@ -61,7 +61,7 @@ export class AlertBannerModel extends HoistModel {
61
61
  return ['primary', 'success', 'warning', 'danger'];
62
62
  }
63
63
 
64
- get iconOptions() {
64
+ get iconOptions(): AlertBannerIconName[] {
65
65
  return [
66
66
  'bullhorn',
67
67
  'check-circle',
@@ -1,13 +1,13 @@
1
1
  import { FormModel } from '@xh/hoist/cmp/form';
2
2
  import { HoistModel, Intent, LoadSpec, PlainObject } from '@xh/hoist/core';
3
- import { AlertBannerSpec } from '@xh/hoist/svc';
3
+ import { AlertBannerIconName, AlertBannerSpec } from '@xh/hoist/svc';
4
4
  export declare class AlertBannerModel extends HoistModel {
5
5
  savedValue: AlertBannerSpec;
6
6
  savedPresets: PlainObject[];
7
7
  formModel: FormModel;
8
8
  bannerModel: any;
9
9
  get intentOptions(): Intent[];
10
- get iconOptions(): string[];
10
+ get iconOptions(): AlertBannerIconName[];
11
11
  constructor();
12
12
  doLoadAsync(loadSpec: LoadSpec): Promise<void>;
13
13
  saveAsync(): Promise<void>;
@@ -1,18 +1,12 @@
1
+ import { IconName } from '@fortawesome/fontawesome-svg-core';
1
2
  import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
2
- import { ReactElement } from 'react';
3
3
  import { HoistProps, Intent, Thunkable } from '@xh/hoist/core';
4
+ import { ReactElement } from 'react';
4
5
  export interface IconProps extends HoistProps, Partial<Omit<FontAwesomeIconProps, 'ref'>> {
5
6
  /** Name of the icon in FontAwesome. */
6
- iconName?: string;
7
- /**
8
- * Prefix / weight of the icon (or "fab" if your app has imported the free-brand-icons pkg).
9
- * - far - Regular
10
- * - fas - Solid
11
- * - fal - Light
12
- * - fat - Thin (yes, unfortunate)
13
- * - fab - Brand (requires optional import, see Toolbox)
14
- */
15
- prefix?: 'far' | 'fas' | 'fal' | 'fat' | 'fab';
7
+ iconName?: IconName;
8
+ /** Weight / family style of the icon. */
9
+ prefix?: HoistIconPrefix;
16
10
  intent?: Intent;
17
11
  /** Optional tooltip string. */
18
12
  title?: string;
@@ -23,27 +17,45 @@ export interface IconProps extends HoistProps, Partial<Omit<FontAwesomeIconProps
23
17
  /** True to skip rendering this Icon. */
24
18
  omit?: Thunkable<boolean>;
25
19
  }
20
+ /**
21
+ * Icon props after defaults applied by Hoist factory methods.
22
+ * @internal
23
+ */
24
+ export interface ResolvedIconProps extends IconProps {
25
+ iconName: IconName;
26
+ prefix: HoistIconPrefix;
27
+ }
28
+ /** Supported FA prefixes, used to request a family-specific variant of an icon. */
29
+ export type HoistIconPrefix = 'far' | 'fas' | 'fal' | 'fat' | 'fab';
26
30
  /**
27
31
  * Singleton class to provide factories for creating standard FontAwesome-based icons.
28
32
  *
29
- * Currently we are importing the licensed "pro" library with additional icons - note this requires
30
- * fetching the FA npm package via a registry URL w/license token.
33
+ * Hoist imports the licensed "pro" library with additional icons - note this requires fetching the
34
+ * FA npm package via a registry URL w/license token.
31
35
  *
32
36
  * See https://fontawesome.com/pro#license.
33
37
  */
34
38
  export declare const Icon: {
35
39
  /**
36
- * Return a standard Hoist FontAwesome-based icon.
40
+ * Return a Hoist element wrapper around a FontAwesome-based icon.
37
41
  *
38
- * Note that in order to use an icon with this factory, its definition must have been already
39
- * imported and registered with FontAwesome via a call to library.add().
42
+ * Note that for an app to use an icon with this factory, its definition must have been already
43
+ * imported and registered with FontAwesome. Apps will find many/most of the icons they need
44
+ * pre-registered and enumerated by the Hoist factories below. Favor those ready-made factories
45
+ * wherever possible for consistency across and within apps.
40
46
  *
41
- * Applications will often not need to use this factory directly when creating specific
42
- * icons enumerated by Hoist. In that case use the supplied factories on the Icon class
43
- * directly (e.g. Icon.add(), Icon.book(), etc.) These factories will delegate to this method,
44
- * with the name of a pre-imported icon preset.
47
+ * If the FA icon of your dreams is not available, however, you can do a one-time import within
48
+ * your app bootstrap code, eg:
49
+ * ```
50
+ * import {library} from '@fortawesome/fontawesome-svg-core';
51
+ * import {faDreamIcon} from '@fortawesome/pro-regular-svg-icons';
52
+ * library.add(faDreamIcon);
53
+ * ```
54
+ * and then pass its string name to this factory: `icon({iconName: 'dream-icon'})`
45
55
  */
46
- icon(opts?: IconProps): any;
56
+ icon(opts: IconProps & {
57
+ iconName: IconName;
58
+ }): any;
47
59
  addressCard(p?: IconProps): any;
48
60
  angleDoubleDown(p?: IconProps): any;
49
61
  angleDoubleLeft(p?: IconProps): any;
@@ -323,32 +335,30 @@ export declare const Icon: {
323
335
  placeholder(opts?: IconProps): any;
324
336
  };
325
337
  /**
326
- * Translate an icon into an html <svg/> tag.
338
+ * Translate an icon into an HTML `<svg>` tag.
327
339
  *
328
- * Not typically used by applications. Applications that need html for an icon, e.g.
329
- * for a grid column renderer should use the 'asHtml' flag on the Icon factory functions
330
- * instead.
340
+ * Not typically used by applications. Applications that need HTML for an icon should use the
341
+ * {@link IconProps.asHtml} flag on the Icon factory functions instead.
331
342
  *
332
- * @param iconElem - react element representing a Hoist Icon component.
333
- * This must be element created by Hoist's built-in Icon factories.
334
- * @returns html of the <svg> tag representing the icon.
343
+ * @param iconElem - React element representing a Hoist Icon component.
344
+ * Must be created by Hoist's built-in Icon factories.
345
+ * @returns HTML string for the icon's `<svg>` tag.
346
+ * @internal
335
347
  */
336
348
  export declare function convertIconToHtml(iconElem: ReactElement): string;
337
349
  /**
338
- * Serialize an icon into a form that can be persisted.
350
+ * Serialize an icon into a JSON format with relevant props for persistence.
339
351
  *
340
- * @param iconElem - react element representing a icon component.
341
- * This must be an element created by Hoist's built-in Icon factories.
342
- * @returns json representation of icon.
352
+ * @param iconElem - React element representing a Hoist Icon component.
353
+ * Must be created by Hoist's built-in Icon factories.
354
+ * @returns JSON representation of icon.
343
355
  */
344
356
  export declare function serializeIcon(iconElem: ReactElement): any;
345
357
  /**
346
- * Deserialize an icon.
347
- *
348
- * This is the inverse operation of serializeIcon().
358
+ * Deserialize an icon - the inverse operation of {@link serializeIcon}.
349
359
  *
350
- * @param iconDef - json representation of icon, produced by serializeIcon.
351
- * @returns react element representing a FontAwesome icon component.
360
+ * @param iconDef - JSON representation of icon, produced by serializeIcon.
361
+ * @returns React element representing a Hoist Icon component.
352
362
  * This is the form of element created by Hoist's built-in Icon class factories.
353
363
  */
354
364
  export declare function deserializeIcon(iconDef: any): ReactElement | string;
@@ -1,13 +1,13 @@
1
+ import { IconName, IconPrefix } from '@fortawesome/fontawesome-svg-core';
1
2
  /**
2
- * Get the raw text of an SVG tag for an icon
3
- * Applications should use the factory methods on Icon instead.
4
- * @internal
3
+ * Get the raw HTML string for an icon's SVG tag.
4
+ * @internal - apps should use the Hoist Icon factories instead with {@link IconProps.asHtml}.
5
5
  */
6
6
  export declare function iconHtml({ iconName, prefix, title, className, size }: {
7
- iconName: any;
8
- prefix: any;
9
- title: any;
10
- className: any;
11
- size: any;
7
+ iconName: IconName;
8
+ prefix: IconPrefix;
9
+ title?: string;
10
+ className?: string;
11
+ size?: string;
12
12
  }): string;
13
13
  export declare function enhanceFaClasses(className: string, size: string): string;
@@ -1,3 +1,4 @@
1
+ import { IconName } from '@fortawesome/fontawesome-svg-core';
1
2
  import { BannerSpec, HoistService, Intent } from '@xh/hoist/core';
2
3
  /**
3
4
  * Service to display an app-wide alert banner, as configured via the Hoist Admin console.
@@ -10,23 +11,23 @@ export declare class AlertBannerService extends HoistService {
10
11
  static instance: AlertBannerService;
11
12
  get lastDismissed(): number;
12
13
  updateBanner(spec: AlertBannerSpec): Promise<void>;
13
- genBannerSpec(message: string, intent: Intent, iconName: string, enableClose: boolean): BannerSpec;
14
+ genBannerSpec(message: string, intent: Intent, iconName: IconName, enableClose: boolean): BannerSpec;
14
15
  private onClose;
15
16
  private isTargetedApp;
16
17
  }
17
- /**
18
- * @internal
19
- */
18
+ /** @internal */
20
19
  export interface AlertBannerSpec {
21
20
  active: boolean;
22
21
  expires: number;
23
22
  publishDate: number;
24
23
  message: string;
25
24
  intent: Intent;
26
- iconName: string;
25
+ iconName: AlertBannerIconName;
27
26
  enableClose: boolean;
28
27
  clientApps: string[];
29
28
  created: number;
30
29
  updated: number;
31
30
  updatedBy: string;
32
31
  }
32
+ /** @internal */
33
+ export type AlertBannerIconName = 'bullhorn' | 'check-circle' | 'exclamation-triangle' | 'times-circle' | 'info-circle' | 'question-circle';
@@ -16,7 +16,7 @@ import {
16
16
  TaskObserver,
17
17
  XH
18
18
  } from '@xh/hoist/core';
19
- import {convertIconToHtml, deserializeIcon} from '@xh/hoist/icon';
19
+ import {convertIconToHtml, deserializeIcon, ResolvedIconProps} from '@xh/hoist/icon';
20
20
  import {showContextMenu} from '@xh/hoist/kit/blueprint';
21
21
  import {GoldenLayout} from '@xh/hoist/kit/golden-layout';
22
22
  import {action, bindable, makeObservable, observable, runInAction} from '@xh/hoist/mobx';
@@ -540,7 +540,7 @@ export class DashContainerModel
540
540
  if (icon) {
541
541
  const $currentIcon = $el.find(iconSelector).first(),
542
542
  currentIconType = $currentIcon ? $currentIcon?.data('icon') : null,
543
- newIconType = icon.props.iconName;
543
+ newIconType = (icon.props as ResolvedIconProps).iconName;
544
544
 
545
545
  if (currentIconType !== newIconType) {
546
546
  const iconSvg = convertIconToHtml(icon);
package/icon/Icon.ts CHANGED
@@ -4,29 +4,23 @@
4
4
  *
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
+ import {IconName} from '@fortawesome/fontawesome-svg-core';
7
8
  import {FontAwesomeIconProps} from '@fortawesome/react-fontawesome';
8
9
  import {div} from '@xh/hoist/cmp/layout';
10
+ import {HoistProps, Intent, Thunkable} from '@xh/hoist/core';
9
11
  import {throwIf} from '@xh/hoist/utils/js';
10
12
  import classNames from 'classnames';
11
13
  import {last, pickBy, split, toLower} from 'lodash';
14
+ import {ReactElement} from 'react';
12
15
  import {iconCmp} from './impl/IconCmp';
13
16
  import {enhanceFaClasses, iconHtml} from './impl/IconHtml';
14
- import {ReactElement} from 'react';
15
- import {HoistProps, Intent, Thunkable} from '@xh/hoist/core';
16
17
 
17
18
  export interface IconProps extends HoistProps, Partial<Omit<FontAwesomeIconProps, 'ref'>> {
18
19
  /** Name of the icon in FontAwesome. */
19
- iconName?: string;
20
+ iconName?: IconName;
20
21
 
21
- /**
22
- * Prefix / weight of the icon (or "fab" if your app has imported the free-brand-icons pkg).
23
- * - far - Regular
24
- * - fas - Solid
25
- * - fal - Light
26
- * - fat - Thin (yes, unfortunate)
27
- * - fab - Brand (requires optional import, see Toolbox)
28
- */
29
- prefix?: 'far' | 'fas' | 'fal' | 'fat' | 'fab';
22
+ /** Weight / family style of the icon. */
23
+ prefix?: HoistIconPrefix;
30
24
 
31
25
  intent?: Intent;
32
26
 
@@ -59,27 +53,50 @@ export interface IconProps extends HoistProps, Partial<Omit<FontAwesomeIconProps
59
53
  omit?: Thunkable<boolean>;
60
54
  }
61
55
 
56
+ /**
57
+ * Icon props after defaults applied by Hoist factory methods.
58
+ * @internal
59
+ */
60
+ export interface ResolvedIconProps extends IconProps {
61
+ iconName: IconName;
62
+ prefix: HoistIconPrefix;
63
+ }
64
+
65
+ /** Supported FA prefixes, used to request a family-specific variant of an icon. */
66
+ export type HoistIconPrefix =
67
+ | 'far' // regular
68
+ | 'fas' // solid
69
+ | 'fal' // light
70
+ | 'fat' // thin
71
+ | 'fab'; // brands (requires optional import, see Toolbox)
72
+
62
73
  /**
63
74
  * Singleton class to provide factories for creating standard FontAwesome-based icons.
64
75
  *
65
- * Currently we are importing the licensed "pro" library with additional icons - note this requires
66
- * fetching the FA npm package via a registry URL w/license token.
76
+ * Hoist imports the licensed "pro" library with additional icons - note this requires fetching the
77
+ * FA npm package via a registry URL w/license token.
67
78
  *
68
79
  * See https://fontawesome.com/pro#license.
69
80
  */
70
81
  export const Icon = {
71
82
  /**
72
- * Return a standard Hoist FontAwesome-based icon.
83
+ * Return a Hoist element wrapper around a FontAwesome-based icon.
73
84
  *
74
- * Note that in order to use an icon with this factory, its definition must have been already
75
- * imported and registered with FontAwesome via a call to library.add().
85
+ * Note that for an app to use an icon with this factory, its definition must have been already
86
+ * imported and registered with FontAwesome. Apps will find many/most of the icons they need
87
+ * pre-registered and enumerated by the Hoist factories below. Favor those ready-made factories
88
+ * wherever possible for consistency across and within apps.
76
89
  *
77
- * Applications will often not need to use this factory directly when creating specific
78
- * icons enumerated by Hoist. In that case use the supplied factories on the Icon class
79
- * directly (e.g. Icon.add(), Icon.book(), etc.) These factories will delegate to this method,
80
- * with the name of a pre-imported icon preset.
90
+ * If the FA icon of your dreams is not available, however, you can do a one-time import within
91
+ * your app bootstrap code, eg:
92
+ * ```
93
+ * import {library} from '@fortawesome/fontawesome-svg-core';
94
+ * import {faDreamIcon} from '@fortawesome/pro-regular-svg-icons';
95
+ * library.add(faDreamIcon);
96
+ * ```
97
+ * and then pass its string name to this factory: `icon({iconName: 'dream-icon'})`
81
98
  */
82
- icon(opts?: IconProps): any {
99
+ icon(opts: IconProps & {iconName: IconName}): any {
83
100
  let {
84
101
  iconName,
85
102
  prefix = 'far',
@@ -908,30 +925,30 @@ export const Icon = {
908
925
  };
909
926
 
910
927
  /**
911
- * Translate an icon into an html <svg/> tag.
928
+ * Translate an icon into an HTML `<svg>` tag.
912
929
  *
913
- * Not typically used by applications. Applications that need html for an icon, e.g.
914
- * for a grid column renderer should use the 'asHtml' flag on the Icon factory functions
915
- * instead.
930
+ * Not typically used by applications. Applications that need HTML for an icon should use the
931
+ * {@link IconProps.asHtml} flag on the Icon factory functions instead.
916
932
  *
917
- * @param iconElem - react element representing a Hoist Icon component.
918
- * This must be element created by Hoist's built-in Icon factories.
919
- * @returns html of the <svg> tag representing the icon.
933
+ * @param iconElem - React element representing a Hoist Icon component.
934
+ * Must be created by Hoist's built-in Icon factories.
935
+ * @returns HTML string for the icon's `<svg>` tag.
936
+ * @internal
920
937
  */
921
938
  export function convertIconToHtml(iconElem: ReactElement): string {
922
939
  throwIf(
923
940
  !(iconElem?.type as any)?.isHoistComponent,
924
941
  'Icon not provided, or not created by a Hoist Icon factory - cannot convert to HTML/SVG.'
925
942
  );
926
- return iconHtml(iconElem.props);
943
+ return iconHtml(iconElem.props as ResolvedIconProps);
927
944
  }
928
945
 
929
946
  /**
930
- * Serialize an icon into a form that can be persisted.
947
+ * Serialize an icon into a JSON format with relevant props for persistence.
931
948
  *
932
- * @param iconElem - react element representing a icon component.
933
- * This must be an element created by Hoist's built-in Icon factories.
934
- * @returns json representation of icon.
949
+ * @param iconElem - React element representing a Hoist Icon component.
950
+ * Must be created by Hoist's built-in Icon factories.
951
+ * @returns JSON representation of icon.
935
952
  */
936
953
  export function serializeIcon(iconElem: ReactElement): any {
937
954
  throwIf(
@@ -939,16 +956,14 @@ export function serializeIcon(iconElem: ReactElement): any {
939
956
  'Icon not provided, or not created by a Hoist Icon factory - cannot serialize.'
940
957
  );
941
958
 
942
- return pickBy(iconElem.props);
959
+ return pickBy(iconElem.props as ResolvedIconProps);
943
960
  }
944
961
 
945
962
  /**
946
- * Deserialize an icon.
947
- *
948
- * This is the inverse operation of serializeIcon().
963
+ * Deserialize an icon - the inverse operation of {@link serializeIcon}.
949
964
  *
950
- * @param iconDef - json representation of icon, produced by serializeIcon.
951
- * @returns react element representing a FontAwesome icon component.
965
+ * @param iconDef - JSON representation of icon, produced by serializeIcon.
966
+ * @returns React element representing a Hoist Icon component.
952
967
  * This is the form of element created by Hoist's built-in Icon class factories.
953
968
  */
954
969
  export function deserializeIcon(iconDef: any): ReactElement | string {
@@ -4,16 +4,27 @@
4
4
  *
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
- import {findIconDefinition, icon} from '@fortawesome/fontawesome-svg-core';
7
+ import {findIconDefinition, icon, IconName, IconPrefix} from '@fortawesome/fontawesome-svg-core';
8
8
  import classNames from 'classnames';
9
9
  import {isString} from 'lodash';
10
10
 
11
11
  /**
12
- * Get the raw text of an SVG tag for an icon
13
- * Applications should use the factory methods on Icon instead.
14
- * @internal
12
+ * Get the raw HTML string for an icon's SVG tag.
13
+ * @internal - apps should use the Hoist Icon factories instead with {@link IconProps.asHtml}.
15
14
  */
16
- export function iconHtml({iconName, prefix, title, className, size}) {
15
+ export function iconHtml({
16
+ iconName,
17
+ prefix = 'far',
18
+ title,
19
+ className,
20
+ size
21
+ }: {
22
+ iconName: IconName;
23
+ prefix: IconPrefix;
24
+ title?: string;
25
+ className?: string;
26
+ size?: string;
27
+ }) {
17
28
  const iconDef = findIconDefinition({prefix, iconName}),
18
29
  classes = enhanceFaClasses(className, size);
19
30
 
@@ -21,9 +32,5 @@ export function iconHtml({iconName, prefix, title, className, size}) {
21
32
  }
22
33
 
23
34
  export function enhanceFaClasses(className: string, size: string) {
24
- let ret = classNames(className, 'fa-fw', 'xh-icon');
25
- if (isString(size)) {
26
- ret = classNames(ret, `fa-${size}`);
27
- }
28
- return ret;
35
+ return classNames(className, 'fa-fw', 'xh-icon', isString(size) ? `fa-${size}` : null);
29
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "71.0.0-SNAPSHOT.1735332336875",
3
+ "version": "71.0.0-SNAPSHOT.1735335976186",
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",
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
+ import {IconName} from '@fortawesome/fontawesome-svg-core';
7
8
  import {BannerModel} from '@xh/hoist/appcontainer/BannerModel';
8
9
  import {markdown} from '@xh/hoist/cmp/markdown';
9
10
  import {BannerSpec, HoistService, Intent, XH} from '@xh/hoist/core';
@@ -47,7 +48,7 @@ export class AlertBannerService extends HoistService {
47
48
  genBannerSpec(
48
49
  message: string,
49
50
  intent: Intent,
50
- iconName: string,
51
+ iconName: IconName,
51
52
  enableClose: boolean
52
53
  ): BannerSpec {
53
54
  const icon = iconName ? Icon.icon({iconName, size: 'lg'}) : null,
@@ -90,19 +91,26 @@ export class AlertBannerService extends HoistService {
90
91
  }
91
92
  }
92
93
 
93
- /**
94
- * @internal
95
- */
94
+ /** @internal */
96
95
  export interface AlertBannerSpec {
97
96
  active: boolean;
98
97
  expires: number;
99
98
  publishDate: number;
100
99
  message: string;
101
100
  intent: Intent;
102
- iconName: string;
101
+ iconName: AlertBannerIconName;
103
102
  enableClose: boolean;
104
103
  clientApps: string[];
105
104
  created: number;
106
105
  updated: number;
107
106
  updatedBy: string;
108
107
  }
108
+
109
+ /** @internal */
110
+ export type AlertBannerIconName =
111
+ | 'bullhorn'
112
+ | 'check-circle'
113
+ | 'exclamation-triangle'
114
+ | 'times-circle'
115
+ | 'info-circle'
116
+ | 'question-circle';