hs-uix 2.1.1 → 2.2.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.
Files changed (49) hide show
  1. package/README.md +3 -1
  2. package/common-components.d.ts +319 -68
  3. package/dist/calendar.js +355 -57
  4. package/dist/calendar.mjs +356 -57
  5. package/dist/common-components.js +3546 -88
  6. package/dist/common-components.mjs +3530 -84
  7. package/dist/datatable.js +108 -18
  8. package/dist/datatable.mjs +108 -18
  9. package/dist/experimental.js +2876 -0
  10. package/dist/experimental.mjs +2883 -0
  11. package/dist/feed.js +267 -38
  12. package/dist/feed.mjs +260 -37
  13. package/dist/filter.js +1379 -0
  14. package/dist/filter.mjs +1334 -0
  15. package/dist/form.js +222 -26
  16. package/dist/form.mjs +227 -27
  17. package/dist/index.js +3208 -287
  18. package/dist/index.mjs +3156 -283
  19. package/dist/kanban.js +282 -62
  20. package/dist/kanban.mjs +273 -61
  21. package/dist/safe.js +9207 -0
  22. package/dist/safe.mjs +9298 -0
  23. package/dist/utils.js +491 -75
  24. package/dist/utils.mjs +491 -75
  25. package/experimental.d.ts +1 -0
  26. package/filter.d.ts +1 -0
  27. package/index.d.ts +45 -3
  28. package/package.json +19 -1
  29. package/safe.d.ts +1 -0
  30. package/src/calendar/README.md +74 -5
  31. package/src/calendar/index.d.ts +95 -1
  32. package/src/common-components/README.md +140 -1
  33. package/src/datatable/README.md +0 -2
  34. package/src/experimental/README.md +126 -0
  35. package/src/experimental/index.d.ts +346 -0
  36. package/src/feed/README.md +69 -0
  37. package/src/feed/index.d.ts +103 -0
  38. package/src/filter/README.md +148 -0
  39. package/src/filter/index.d.ts +221 -0
  40. package/src/form/README.md +132 -4
  41. package/src/form/index.d.ts +82 -1
  42. package/src/kanban/README.md +119 -6
  43. package/src/kanban/index.d.ts +153 -2
  44. package/src/safe/README.md +108 -0
  45. package/src/safe/index.d.ts +158 -0
  46. package/src/utils/README.md +39 -0
  47. package/src/wizard/README.md +158 -0
  48. package/src/wizard/index.d.ts +138 -0
  49. package/utils.d.ts +17 -0
package/README.md CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  CollectionToolbar,
27
27
  } from "hs-uix/common-components";
28
28
  import { CrmDataTable, CrmKanban, formatCurrency, formatDate } from "hs-uix/utils";
29
+ import { SafeIcon, SafeEmptyState, SafeDataTable } from "hs-uix/safe";
29
30
 
30
31
  // or import everything from the root
31
32
  import { DataTable, FormBuilder, Kanban, Feed, Calendar, Icon } from "hs-uix";
@@ -43,8 +44,9 @@ Requires `react` >= 18.0.0 and `@hubspot/ui-extensions` >= 0.14.0 as peer depend
43
44
  | **Feed** | Activity feed / timeline with a standard item shape, date grouping, load-more pagination, and HubSpot-native item regions | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/feed/README.md) |
44
45
  | **Calendar** | Presentational month/week/day/agenda calendar with search, filters, date navigation, event overlays, and experimental Gantt view | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/calendar/README.md) |
45
46
  | **Common Components** | Thin visual wrappers and shared collection primitives — `Icon`, `AutoTag`, `AutoStatusTag`, `AvatarStack`, `CrmLookupSelect`, `CollectionToolbar`, `CollectionFilterControl`, `CollectionSortSelect`, `CollectionCount`, and more | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/common-components/README.md) |
47
+ | **Safe wrappers** | Hardened drop-ins for failure-prone natives — `SafeIcon` (alias-repair + visible placeholder), `SafeEmptyState` (`imageName` fallback instead of a throw), `SafeStatisticsTrend`, `SafePopover` (auto-padding), and array-coercing `SafeDataTable` / `SafeSelect` / … that degrade to empty states instead of blanking the page | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/safe/README.md) |
46
48
  | **CRM data** | `CrmDataTable` / `CrmKanban` — batch-fetching, client-side-paginating CRM table & board, plus the `useCrmSearch*` hooks behind them | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/utils/README.md) |
47
- | **Utils** | Pure helpers for formatting, options, HubSpot value guards, tag-variant inference, collection filtering/searching, and active-filter chips | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/utils/README.md) |
49
+ | **Utils** | Pure helpers for formatting, options, HubSpot value guards, tag-variant inference, collection filtering/searching, active-filter chips, and RFC 6902 JSON Patch applying (`applyPatches`) | [Full documentation](https://github.com/05bmckay/hs-uix/blob/main/src/utils/README.md) |
48
50
 
49
51
  ---
50
52
 
@@ -60,6 +60,133 @@ export interface DateDirectionLabels {
60
60
  desc: string;
61
61
  }
62
62
 
63
+ /** HubSpot DateInput value object — `month` is 0-indexed (0 = January). */
64
+ export interface DateRangePickerDateValue {
65
+ year: number;
66
+ month: number;
67
+ date: number;
68
+ }
69
+
70
+ /** The explicit `is between` date range shape. */
71
+ export interface DateRangePickerRangeValue {
72
+ from?: DateRangePickerDateValue | null;
73
+ to?: DateRangePickerDateValue | null;
74
+ }
75
+
76
+ export type DateRangePickerOperator =
77
+ | "InRollingDateRange"
78
+ | "Equal"
79
+ | "BeforeDateStaticOrDynamic"
80
+ | "AfterDateStaticOrDynamic"
81
+ | "InRange"
82
+ | "GreaterRolling"
83
+ | "LessRolling"
84
+ | "Known"
85
+ | "NotKnown";
86
+
87
+ export type DateRangePickerRollingUnit = "day" | "week" | "month" | "year";
88
+ export type DateRangePickerRollingDirection = "backward" | "forward";
89
+
90
+ export interface DateRangePickerPresetValue {
91
+ operator: "InRollingDateRange";
92
+ preset?: string;
93
+ }
94
+
95
+ export interface DateRangePickerRollingValue {
96
+ operator: "GreaterRolling" | "LessRolling";
97
+ amount?: number;
98
+ unit?: DateRangePickerRollingUnit;
99
+ direction?: DateRangePickerRollingDirection;
100
+ }
101
+
102
+ export interface DateRangePickerSingleDateValue {
103
+ operator: "Equal" | "BeforeDateStaticOrDynamic" | "AfterDateStaticOrDynamic";
104
+ date?: DateRangePickerDateValue | null;
105
+ }
106
+
107
+ export interface DateRangePickerExplicitRangeValue extends DateRangePickerRangeValue {
108
+ operator: "InRange";
109
+ }
110
+
111
+ export interface DateRangePickerPresenceValue {
112
+ operator: "Known" | "NotKnown";
113
+ }
114
+
115
+ export type DateRangePickerValue =
116
+ | DateRangePickerRangeValue
117
+ | DateRangePickerPresetValue
118
+ | DateRangePickerSingleDateValue
119
+ | DateRangePickerRollingValue
120
+ | DateRangePickerExplicitRangeValue
121
+ | DateRangePickerPresenceValue;
122
+
123
+ export interface DateRangePickerPresetOption {
124
+ label: string;
125
+ /** A preset key understood by presetToRange, or any key when getRange is given. */
126
+ value: string;
127
+ /** Fully custom preset: compute the range yourself from `now`. */
128
+ getRange?: (now: Date) => DateRangePickerRangeValue;
129
+ }
130
+
131
+ export interface DateRangePickerChangeMeta {
132
+ operator: DateRangePickerOperator;
133
+ /** Selected controlling CRM property, when field selection is enabled. */
134
+ field?: string | null;
135
+ /** The preset key that produced the range, or null for manual edits / clear. */
136
+ preset: string | null;
137
+ range?: DateRangePickerRangeValue | null;
138
+ previousOperator?: DateRangePickerOperator;
139
+ }
140
+
141
+ export interface DateRangePickerProps {
142
+ /** Controlled date filter value. Range sides may be null for an open-ended range. */
143
+ value?: DateRangePickerValue;
144
+ /** Initial date filter value for uncontrolled usage. */
145
+ defaultValue?: DateRangePickerValue;
146
+ /** Fires with normalized values. Explicit ranges only emit when valid (from <= to, or a side null). */
147
+ onChange?: (range: DateRangePickerValue, meta: DateRangePickerChangeMeta) => void;
148
+ /** Optional group label rendered above the control. */
149
+ label?: ReactNode;
150
+ /** Base for inner input names (`${name}-from`, `${name}-to`, `${name}-preset`). */
151
+ name?: string;
152
+ /** Controlled CRM date/datetime property value for the field dropdown. */
153
+ field?: string;
154
+ /** Initial CRM date/datetime property value for uncontrolled field selection. */
155
+ defaultField?: string;
156
+ onFieldChange?: (field: string) => void;
157
+ /** Render a controlling field dropdown above the operator. */
158
+ showFieldSelect?: boolean;
159
+ fieldOptions?: Array<{ label: ReactNode; value: string }>;
160
+ operator?: DateRangePickerOperator;
161
+ defaultOperator?: DateRangePickerOperator;
162
+ onOperatorChange?: (operator: DateRangePickerOperator) => void;
163
+ showOperatorSelect?: boolean;
164
+ operatorOptions?: Array<{ label: ReactNode; value: DateRangePickerOperator }>;
165
+ /** true = HS_DATE_PRESETS Select, false = none, or a custom preset array. */
166
+ presets?: boolean | DateRangePickerPresetOption[];
167
+ rollingUnitOptions?: Array<{ label: ReactNode; value: string }>;
168
+ direction?: "row" | "column";
169
+ /** Show a Clear link when the range is non-empty. */
170
+ clearable?: boolean;
171
+ min?: DateRangePickerDateValue;
172
+ max?: DateRangePickerDateValue;
173
+ fromLabel?: string;
174
+ toLabel?: string;
175
+ dateLabel?: string;
176
+ /** Keep DateInput labels visible. Defaults to false for compact filter rows. */
177
+ showDateLabels?: boolean;
178
+ /** DateInput display format. Default "medium". */
179
+ format?: "short" | "long" | "medium" | "standard" | "YYYY-MM-DD" | "L" | "LL" | "ll";
180
+ presetPlaceholder?: string;
181
+ customPresetLabel?: string;
182
+ clearLabel?: ReactNode;
183
+ invalidRangeMessage?: string;
184
+ readOnly?: boolean;
185
+ gap?: string;
186
+ /** Minimum column width for the field-enabled flexible AutoGrid layout. */
187
+ gridColumnWidth?: number;
188
+ }
189
+
63
190
  export interface AvatarStackItemObject {
64
191
  letter?: string;
65
192
  color?: string;
@@ -100,6 +227,61 @@ export interface AvatarStackProps {
100
227
  alt?: string;
101
228
  }
102
229
 
230
+ export type IconSize =
231
+ | number
232
+ | "xs"
233
+ | "extra-small"
234
+ | "sm"
235
+ | "small"
236
+ | "md"
237
+ | "med"
238
+ | "medium"
239
+ | "lg"
240
+ | "large"
241
+ | "xl"
242
+ | "extra-large";
243
+
244
+ export interface IconPathObject {
245
+ d: string;
246
+ fill?: string;
247
+ fillRule?: "nonzero" | "evenodd";
248
+ }
249
+
250
+ export type IconPath = string | IconPathObject;
251
+
252
+ export interface IconEntry {
253
+ /** Defaults to "0 0 24 24" when omitted. */
254
+ viewBox?: string;
255
+ paths: IconPath[];
256
+ /** Optional transform applied to all paths (e.g. a mirror/rotation). */
257
+ transform?: string;
258
+ }
259
+
260
+ export interface IconProps {
261
+ /** A registered glyph name (native or custom). Unknown names render nothing. */
262
+ name: string;
263
+ /** A semantic token ("inherit" | "alert" | "warning" | "success") or any CSS color. */
264
+ color?: string;
265
+ size?: IconSize;
266
+ /** Accessible label for screen readers. */
267
+ screenReaderText?: string;
268
+ /** Passed through to native HubSpot Icon when possible; fallback Image also receives it. */
269
+ onClick?: (...args: unknown[]) => void;
270
+ /** Passed through to native HubSpot Icon when possible; fallback Image also receives it. */
271
+ href?: string | { url: string; external?: boolean };
272
+ }
273
+
274
+ export interface IconDataUriResult {
275
+ src: string;
276
+ width: number;
277
+ height: number;
278
+ }
279
+
280
+ export interface IconDataUriOptions {
281
+ size?: IconSize;
282
+ color?: string;
283
+ }
284
+
103
285
  export interface CollectionFilterConfig {
104
286
  name: string;
105
287
  type?: "select" | "multiselect" | "dateRange" | string;
@@ -273,6 +455,102 @@ export interface CrmLookupSelectProps {
273
455
  selectProps?: Record<string, unknown>;
274
456
  }
275
457
 
458
+ /** Dotted property path ("properties.domain") or accessor function. */
459
+ export type CrmRecordPickerFieldAccessor =
460
+ | string
461
+ | ((record: Record<string, unknown>) => unknown);
462
+
463
+ export type CrmRecordPickerId = string | number;
464
+
465
+ export type CrmRecordPickerRecord = Record<string, unknown>;
466
+
467
+ /** A scalar or array of record ids and/or record objects. */
468
+ export type CrmRecordPickerValue =
469
+ | CrmRecordPickerId
470
+ | CrmRecordPickerRecord
471
+ | Array<CrmRecordPickerId | CrmRecordPickerRecord>;
472
+
473
+ export interface CrmRecordPickerOption {
474
+ label: ReactNode;
475
+ value: CrmRecordPickerId;
476
+ description?: string;
477
+ }
478
+
479
+ export interface CrmRecordPickerCreateConfig {
480
+ /** Static label or `(term) => label` formatter. Default `Create "<term>"`. */
481
+ label?: string | ((term: string) => string);
482
+ /** Create the record for the search term; return the new record or its id. */
483
+ onCreate: (
484
+ searchTerm: string
485
+ ) =>
486
+ | Promise<CrmRecordPickerRecord | CrmRecordPickerId>
487
+ | CrmRecordPickerRecord
488
+ | CrmRecordPickerId;
489
+ }
490
+
491
+ export interface CrmRecordPickerProps {
492
+ objectType: "contact" | "contacts" | "company" | "companies" | "deal" | "deals" | string;
493
+ properties?: string[];
494
+ labelField?: CrmRecordPickerFieldAccessor;
495
+ descriptionField?: CrmRecordPickerFieldAccessor;
496
+ value?: CrmRecordPickerValue;
497
+ defaultValue?: CrmRecordPickerValue;
498
+ /**
499
+ * Multi mode passes (ids, records) arrays; single mode passes a scalar id
500
+ * (or null) and the matching record (or null). Records never seen by the
501
+ * picker come back as `{ objectId: id }` stubs.
502
+ */
503
+ onChange?: (
504
+ ids: CrmRecordPickerId[] | CrmRecordPickerId | null,
505
+ records: CrmRecordPickerRecord[] | CrmRecordPickerRecord | null
506
+ ) => void;
507
+ multi?: boolean;
508
+ max?: number;
509
+ placeholder?: string;
510
+ label?: string;
511
+ name?: string;
512
+ required?: boolean;
513
+ readOnly?: boolean;
514
+ error?: boolean;
515
+ validationMessage?: string;
516
+ description?: string;
517
+ tooltip?: string;
518
+ variant?: "transparent" | "input";
519
+ pageLength?: number;
520
+ debounce?: number;
521
+ minSearchLength?: number;
522
+ filterMap?: (
523
+ filters: Record<string, unknown>,
524
+ params: Record<string, unknown>
525
+ ) => unknown;
526
+ allowCreate?: false | CrmRecordPickerCreateConfig;
527
+ fallbackLabel?: string;
528
+ format?: Record<string, unknown>;
529
+ baseConfig?: Record<string, unknown>;
530
+ onSearchChange?: (query: string) => void;
531
+ [key: string]: unknown;
532
+ }
533
+
534
+ export interface CrmRecordPickerCreateOptionRules {
535
+ allowCreate?: false | true | CrmRecordPickerCreateConfig;
536
+ searchTerm?: string;
537
+ options?: CrmRecordPickerOption[];
538
+ searching?: boolean;
539
+ createPending?: boolean;
540
+ atMax?: boolean;
541
+ }
542
+
543
+ export interface CrmRecordPickerOptionConfig {
544
+ labelField?: CrmRecordPickerFieldAccessor;
545
+ descriptionField?: CrmRecordPickerFieldAccessor;
546
+ fallbackLabel?: string;
547
+ }
548
+
549
+ export interface CrmRecordPickerSelection {
550
+ ids: CrmRecordPickerId[];
551
+ records: CrmRecordPickerRecord[];
552
+ }
553
+
276
554
  export interface StyledTextFormat {
277
555
  fontWeight?: "bold" | "demibold" | "regular" | number;
278
556
  italic?: boolean;
@@ -362,61 +640,19 @@ export interface SpinnerProps {
362
640
  truncate?: boolean | { tooltipText?: string };
363
641
  }
364
642
 
365
- export type IconSize =
366
- | number
367
- | "xs"
368
- | "extra-small"
369
- | "sm"
370
- | "small"
371
- | "md"
372
- | "med"
373
- | "medium"
374
- | "lg"
375
- | "large"
376
- | "xl"
377
- | "extra-large";
378
-
379
- export interface IconPathObject {
380
- d: string;
381
- fill?: string;
382
- fillRule?: "nonzero" | "evenodd";
383
- }
384
-
385
- export type IconPath = string | IconPathObject;
386
-
387
- export interface IconEntry {
388
- /** Defaults to "0 0 24 24" when omitted. */
389
- viewBox?: string;
390
- paths: IconPath[];
391
- /** Optional transform applied to all paths (e.g. a mirror/rotation). */
392
- transform?: string;
393
- }
394
-
395
- export interface IconProps {
396
- /** A registered glyph name (native or custom). Unknown names render nothing. */
397
- name: string;
398
- /** A semantic token ("inherit" | "alert" | "warning" | "success") or any CSS color. */
399
- color?: string;
400
- size?: IconSize;
401
- /** Accessible label for screen readers. */
402
- screenReaderText?: string;
403
- /** Passed through to native HubSpot Icon when possible; fallback Image also receives it. */
404
- onClick?: (...args: unknown[]) => void;
405
- /** Passed through to native HubSpot Icon when possible; fallback Image also receives it. */
406
- href?: string | { url: string; external?: boolean };
407
- }
408
-
409
- export interface IconDataUriResult {
410
- src: string;
411
- width: number;
412
- height: number;
413
- }
414
-
415
- export interface IconDataUriOptions {
416
- size?: IconSize;
417
- color?: string;
418
- }
419
-
643
+ export declare function AutoTag(props: AutoTagProps): ReactNode;
644
+ export declare function AutoStatusTag(props: AutoStatusTagProps): ReactNode;
645
+ export declare function ActiveFilterChips(props: ActiveFilterChipsProps): ReactNode;
646
+ export declare function CollectionCount(props: CollectionCountProps): ReactNode;
647
+ export declare function formatCollectionCount(params: FormatCollectionCountParams): ReactNode;
648
+ export declare function CollectionFilterControl(props: CollectionFilterControlProps): ReactNode;
649
+ export declare function CollectionSortSelect(props: CollectionSortSelectProps): ReactNode;
650
+ export declare function CollectionToolbar(props: CollectionToolbarProps): ReactNode;
651
+ export declare function SectionHeader(props: SectionHeaderProps): ReactNode;
652
+ export declare function KeyValueList(props: KeyValueListProps): ReactNode;
653
+ export declare function AvatarStack(props: AvatarStackProps): ReactNode;
654
+ export declare function CrmLookupSelect(props: CrmLookupSelectProps): ReactNode;
655
+ export declare function CrmRecordPicker(props: CrmRecordPickerProps): ReactNode;
420
656
  export declare function Icon(props: IconProps): ReactNode;
421
657
  /** Custom glyph names registered in this library (excludes native names). */
422
658
  export declare const ICON_NAMES: string[];
@@ -431,19 +667,6 @@ export declare function makeIconDataUri(
431
667
  ): IconDataUriResult | null;
432
668
  /** Parse a raw `<svg>` string into a registry entry (drops mask/defs, keeps per-path fills). */
433
669
  export declare function svgToIconEntry(raw: string): IconEntry;
434
-
435
- export declare function AutoTag(props: AutoTagProps): ReactNode;
436
- export declare function AutoStatusTag(props: AutoStatusTagProps): ReactNode;
437
- export declare function ActiveFilterChips(props: ActiveFilterChipsProps): ReactNode;
438
- export declare function CollectionCount(props: CollectionCountProps): ReactNode;
439
- export declare function formatCollectionCount(params: FormatCollectionCountParams): ReactNode;
440
- export declare function CollectionFilterControl(props: CollectionFilterControlProps): ReactNode;
441
- export declare function CollectionSortSelect(props: CollectionSortSelectProps): ReactNode;
442
- export declare function CollectionToolbar(props: CollectionToolbarProps): ReactNode;
443
- export declare function SectionHeader(props: SectionHeaderProps): ReactNode;
444
- export declare function KeyValueList(props: KeyValueListProps): ReactNode;
445
- export declare function AvatarStack(props: AvatarStackProps): ReactNode;
446
- export declare function CrmLookupSelect(props: CrmLookupSelectProps): ReactNode;
447
670
  export declare function StyledText(props: StyledTextProps): ReactNode;
448
671
  export declare function Spinner(props: SpinnerProps): ReactNode;
449
672
  export declare const SPINNERS: Record<SpinnerName, SpinnerPreset>;
@@ -459,6 +682,32 @@ export declare function makeStyledTextDataUri(
459
682
  options?: StyledTextDataUriOptions
460
683
  ): StyledTextDataUriResult;
461
684
 
685
+ export declare function DateRangePicker(props: DateRangePickerProps): ReactNode;
686
+ /** Translate an HS_DATE_PRESETS key into a { from, to } range. Null for unknown/custom/empty keys. */
687
+ export declare function presetToRange(
688
+ presetKey: string | null | undefined,
689
+ now?: Date
690
+ ): DateRangePickerRangeValue | null;
691
+ /** Convert a JS Date to a HubSpot date value object. Null for invalid input. */
692
+ export declare function toHsDateValue(date: Date): DateRangePickerDateValue | null;
693
+ /** Sort-style comparator for HubSpot date value objects; null sides compare as 0. */
694
+ export declare function compareHsDateValues(
695
+ a: DateRangePickerDateValue | null | undefined,
696
+ b: DateRangePickerDateValue | null | undefined
697
+ ): number;
698
+ /** True when the range is open-ended or from <= to. */
699
+ export declare function isValidDateRange(range: DateRangePickerRangeValue | null | undefined): boolean;
700
+ /** Sentinel preset value meaning "the user picked dates by hand". */
701
+ export declare const DATE_RANGE_CUSTOM_VALUE: "custom";
702
+ export declare const DATE_FILTER_OPERATORS: Array<{
703
+ label: string;
704
+ value: DateRangePickerOperator;
705
+ }>;
706
+ export declare const DATE_ROLLING_UNIT_OPTIONS: Array<{
707
+ label: string;
708
+ value: string;
709
+ }>;
710
+
462
711
  export declare const HS_DATE_PRESETS: DatePresetOption[];
463
712
  export declare const HS_DATE_DIRECTION_LABELS: DateDirectionLabels;
464
713
  export declare const HS_FONT_FAMILY: string;
@@ -466,6 +715,8 @@ export declare const HS_TEXT_COLOR: string;
466
715
  export declare const HS_SUBTLE_BG: string;
467
716
  export declare const HS_MUTED_TEXT: string;
468
717
  export declare const HS_NEUTRAL_CHIP: string;
718
+ /** Skeleton placeholder gray. */
719
+ export declare const SKELETON_FILL: string;
469
720
  export declare const HS_TAG_SUBTLE_BORDER: string;
470
721
  export declare const HS_TAG_TEXT_COLOR: string;
471
722
  export declare const HS_TAG_FONT_SIZE: number;