@reykjavik/hanna-react 0.10.70 → 0.10.71

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/Alert.d.ts CHANGED
@@ -36,8 +36,7 @@ export declare type AlertProps = {
36
36
  /** Callback that fires when the alert has closed/transitoned out */
37
37
  onClosed: () => void;
38
38
  }, {
39
- /**
40
- * @deprecated This signature with the `event` argument will be removed in hanna-react v0.9
39
+ /** @deprecated This signature with the `event` argument will be removed in hanna-react v0.11
41
40
  *
42
41
  * Return `false` to prevent the alert from closing
43
42
  */
package/ArticleCards.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Cleanup } from '@reykjavik/hanna-utils';
2
2
  import { ImageCardListProps, ImageCardProps } from './_abstract/_CardList';
3
- export declare type ArticleCardProps = ImageCardProps;
3
+ export declare type ArticleCardsItemProps = ImageCardProps;
4
+ /** @deprecated Use `ArticleCardsItemProps` instead (Remove in v0.11) */
5
+ export declare type ArticleCardProps = ArticleCardsItemProps;
4
6
  export declare type ArticleCardsProps = Cleanup<Pick<ImageCardListProps, 'cards' | 'imgPlaceholder'>>;
5
7
  declare const ArticleCards: (props: ArticleCardsProps) => JSX.Element;
6
8
  export default ArticleCards;
package/BasicTable.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { TableProps } from '@hugsmidjan/react/Table';
2
+ import { EitherObj } from '@reykjavik/hanna-utils';
2
3
  import { SeenProp } from './utils/seenEffect';
3
4
  export declare type BasicTableProps = {
4
5
  compact?: boolean;
5
6
  type?: 'text' | 'number';
6
7
  children?: undefined;
7
8
  modifier?: string;
9
+ } & EitherObj<{
8
10
  fullWidth?: boolean;
11
+ }, {
9
12
  align?: 'right';
10
- } & SeenProp & Omit<TableProps, 'className' | 'children'>;
13
+ }> & SeenProp & Omit<TableProps, 'className' | 'children'>;
11
14
  declare const BasicTable: (props: BasicTableProps) => JSX.Element;
12
15
  export default BasicTable;
package/CHANGELOG.md CHANGED
@@ -4,6 +4,37 @@
4
4
 
5
5
  - ... <!-- Add new lines here. -->
6
6
 
7
+ ## 0.10.71
8
+
9
+ _2022-11-23_
10
+
11
+ - feat: Add prop `onFilesRejected` to `FileInputProps`
12
+ - feat: Add prop `itemCount` for all Carousel-related components with
13
+ `children` — drop requirement for children to be an Array.
14
+ - feat(ts): Export `ArticleCardsItemProps`, deprecate `ArticleCardProps`
15
+ - feat(ts): Only allow either `align="right"` or `fullWidth` on `BasicTable`
16
+ - feat: Make `SiteSearchAutocompleteProps.renderSuggestion` optional
17
+ - feat: Add `FooterInfoGroup.main`, deprecate `FooterInfoGroup.role`
18
+ - `FileInput`:
19
+ - feat: Add prop `lang` (default: `'is'`)
20
+ - feat: Make prop `removeFileText` optional
21
+ - fix: File-sizes are now formatted based on `lang` prop
22
+ - `ShareButton`:
23
+ - fix: Add support for Polish
24
+ - fix: Make Icelandic the default/fallback locale
25
+ - fix: Swap in Icelandic and English `emailSubject`s
26
+ - fix: Lingering `--focus` state when keyboard navigating from `DatePicker`
27
+ - fix: Suppress Autocomplete suggestion container until suggestions arrive
28
+ - fix: Disable `button` element when `SearchInput` is disabled or readonly
29
+ - fix: Add missing `title` prop on `IframeBlock`
30
+ - fix: Set default value for empty `WizardStepper` step labels
31
+ - fix: Add missing prop `name` to `DatePicker`
32
+ - fix: Make `ContentArticleProps.meta` optional
33
+ - fix: Suppress `<hr>` in `ContentArticleProps` when `relatedLinks` is missing
34
+ - fix: Make `InfoBlockProps.subTitle` optional
35
+ - fix: Clicks inside `.Datepicker .FormField__input` div always focus `input`
36
+ - fix(ts): Remove unused (`never`) props from `ModalProps`
37
+
7
38
  ## 0.10.70
8
39
 
9
40
  _2022-09-28_
@@ -1,9 +1,9 @@
1
1
  import { TogglerGroupFieldOptions, TogglerGroupFieldProps } from './_abstract/_TogglerGroupField';
2
2
  export declare type CheckboxButtonsGroupProps = TogglerGroupFieldProps & {
3
3
  value?: Array<string>;
4
- /** @deprecated (Will be removed in v0.9) */
4
+ /** @deprecated (Will be removed in v0.11) */
5
5
  columns?: '2col' | '3col';
6
- /** @deprecated (Will be removed in v0.9) */
6
+ /** @deprecated (Will be removed in v0.11) */
7
7
  layout?: 'slim';
8
8
  };
9
9
  export declare type CheckboxButtonsGroupOptions = TogglerGroupFieldOptions;
@@ -5,7 +5,7 @@ import { ContentImageProps } from './ContentImage';
5
5
  import { RelatedLinksProps } from './RelatedLinks';
6
6
  export declare type ContentArticleProps = {
7
7
  /** Date, author, etc. */
8
- meta: ArticleMetaProps['items'];
8
+ meta?: ArticleMetaProps['items'];
9
9
  headline: string;
10
10
  headlineTag?: 'h1' | 'h2';
11
11
  topImage?: ContentImageProps;
package/ContentArticle.js CHANGED
@@ -10,15 +10,16 @@ const RelatedLinks_1 = tslib_1.__importDefault(require("./RelatedLinks"));
10
10
  const TextBlock_1 = tslib_1.__importDefault(require("./TextBlock"));
11
11
  const VSpacer_1 = tslib_1.__importDefault(require("./VSpacer"));
12
12
  const ContentArticle = (props) => {
13
+ const { relatedLinks } = props;
13
14
  const [ref] = (0, seenEffect_1.useSeenEffect)(props.startSeen);
14
15
  return (react_1.default.createElement("div", { className: "ContentArticle", ref: ref },
15
- react_1.default.createElement(ArticleMeta_1.default, { items: props.meta }),
16
+ props.meta && react_1.default.createElement(ArticleMeta_1.default, { items: props.meta }),
16
17
  react_1.default.createElement(Heading_1.default, { forceH1: props.headlineTag === 'h1' }, props.headline),
17
18
  react_1.default.createElement(TextBlock_1.default, { startSeen: true },
18
19
  props.topImage && react_1.default.createElement(ContentImage_1.default, Object.assign({}, props.topImage)),
19
20
  props.body),
20
- react_1.default.createElement(VSpacer_1.default, { size: "small" },
21
- react_1.default.createElement("hr", null)),
22
- props.relatedLinks && react_1.default.createElement(RelatedLinks_1.default, Object.assign({}, props.relatedLinks))));
21
+ relatedLinks && relatedLinks.links.length > 0 && (react_1.default.createElement(VSpacer_1.default, { size: "small" },
22
+ react_1.default.createElement("hr", null))),
23
+ relatedLinks && react_1.default.createElement(RelatedLinks_1.default, Object.assign({}, relatedLinks))));
23
24
  };
24
25
  exports.default = ContentArticle;
package/Datepicker.d.ts CHANGED
@@ -4,6 +4,7 @@ export declare type DatepickerProps = {
4
4
  small?: boolean;
5
5
  placeholder?: string;
6
6
  value?: Date;
7
+ name?: string;
7
8
  startDate?: Date;
8
9
  endDate?: Date;
9
10
  minDate?: Date;
package/Datepicker.js CHANGED
@@ -36,19 +36,19 @@ const i18n = {
36
36
  },
37
37
  };
38
38
  const Datepicker = (props) => {
39
- const { className, id, label, hideLabel, assistText, disabled, readOnly, invalid, errorMessage, required, reqText, placeholder, small, localeCode, dateFormat = 'd.M.yyy', initialDate, value = initialDate, startDate, endDate, minDate, maxDate, isStartDate = false, isEndDate = false, onChange, datepickerExtraProps, ssr, inputRef, } = props;
39
+ const { className, id, label, hideLabel, assistText, disabled, readOnly, invalid, errorMessage, required, reqText, placeholder, small, localeCode, dateFormat = 'd.M.yyy', initialDate, value = initialDate, name, startDate, endDate, minDate, maxDate, isStartDate = false, isEndDate = false, onChange, datepickerExtraProps, ssr, inputRef, } = props;
40
40
  const domid = (0, hooks_1.useDomid)(id);
41
41
  const txts = (localeCode && i18n[localeCode]) || {};
42
42
  const filled = !!value;
43
43
  const empty = !filled && !placeholder;
44
44
  return (react_1.default.createElement(FormField_1.default, { className: (0, getBemClass_1.default)('Datepicker', [], className), ssr: ssr, label: label, small: small, assistText: assistText, hideLabel: hideLabel, invalid: invalid, required: required, reqText: reqText, disabled: disabled, readOnly: readOnly, filled: filled, empty: empty, errorMessage: errorMessage, renderInput: (className, inputProps, addFocusProps) => {
45
- return (react_1.default.createElement("div", { className: className.input, ref: inputRef &&
45
+ return (react_1.default.createElement("div", Object.assign({ className: className.input, onClick: (e) => e.currentTarget.querySelector('input').focus(), ref: inputRef &&
46
46
  ((elm) => {
47
47
  inputRef.current =
48
48
  (elm === null || elm === void 0 ? void 0 : elm.querySelector('input')) || undefined;
49
49
  return elm;
50
- }) },
51
- react_1.default.createElement(react_datepicker_1.default, Object.assign({ id: domid, required: inputProps.required, disabled: inputProps.disabled, readOnly: inputProps.readOnly, selected: value, locale: localeCode, dateFormat: dateFormat, onChange: (date) => {
50
+ }) }, addFocusProps()),
51
+ react_1.default.createElement(react_datepicker_1.default, Object.assign({ id: domid, required: inputProps.required, disabled: inputProps.disabled, readOnly: inputProps.readOnly, selected: value, name: name, locale: localeCode, dateFormat: dateFormat, onChange: (date) => {
52
52
  onChange(date || undefined);
53
53
  const inputElm = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current;
54
54
  if (inputElm) {
@@ -60,7 +60,7 @@ const Datepicker = (props) => {
60
60
  minDate: minDate, maxDate: maxDate, startDate: startDate, endDate: endDate, selectsStart: isStartDate, selectsEnd: isEndDate, formatWeekDay: (weekday) => {
61
61
  // TODO: if we use costom locale we don't need this
62
62
  return weekday.charAt(0).toUpperCase();
63
- }, showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, showMonthDropdown: true }, inputProps, txts, addFocusProps(datepickerExtraProps)))));
63
+ }, showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, showMonthDropdown: true }, inputProps, txts, datepickerExtraProps))));
64
64
  } }));
65
65
  };
66
66
  exports.default = Datepicker;
@@ -16,7 +16,7 @@ export declare const releasePreview: (file: CustomFile) => void;
16
16
  /**
17
17
  * Small+stupid file size pretty-printer.
18
18
  */
19
- export declare const formatBytes: (bytes: number, decimals?: number) => string;
19
+ export declare const formatBytes: (bytes: number, lang?: string, decimals?: number) => string;
20
20
  /**
21
21
  * Figures out how to handle adding files to a FileInput
22
22
  * Which files to retaine, which too delete, and
@@ -22,17 +22,24 @@ const releasePreview = (file) => {
22
22
  delete file.preview;
23
23
  };
24
24
  exports.releasePreview = releasePreview;
25
+ // ---------------------------------------------------------------------------
26
+ const k = 1024;
27
+ const kThreshold = 970 / k; // Snap up a unit level at this point
28
+ const units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB' /*, 'EB', 'ZB', 'YB' */];
29
+ const decimalSymbols = { is: ',', en: '.', pl: ',' };
25
30
  /**
26
31
  * Small+stupid file size pretty-printer.
27
32
  */
28
- const formatBytes = (bytes, decimals = 2) => {
33
+ const formatBytes = (bytes, lang = 'is', decimals = 2) => {
29
34
  if (bytes === 0) {
30
35
  return '0 Bytes';
31
36
  }
32
- const k = 1024;
33
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
34
- const i = Math.floor(Math.log(bytes) / Math.log(k));
35
- return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
37
+ const i = Math.min(Math.floor(Math.log(Math.abs(bytes) / kThreshold) / Math.log(k)), units.length - 1);
38
+ const scaled = bytes / Math.pow(k, i);
39
+ const formatted = (parseFloat(scaled.toFixed(decimals)) + '').replace('.',
40
+ // NOTE: As of 2022-11 Chrome still doesn't support Icelandic
41
+ decimalSymbols[lang] || (1.1).toLocaleString(lang)[1]);
42
+ return `${formatted} ${units[i]}`;
36
43
  };
37
44
  exports.formatBytes = formatBytes;
38
45
  /**
@@ -9,7 +9,7 @@ const DefaultFileList = (props) => {
9
9
  return null;
10
10
  }
11
11
  return (react_1.default.createElement("ul", { className: "FileInput__filelist" }, files.map((file) => (react_1.default.createElement("li", { key: file.name, className: "FileInput__file" },
12
- react_1.default.createElement("button", { className: "FileInput__file-remove", type: "button", onClick: () => removeFile(file), "aria-label": removeFileText }, removeFileText),
12
+ react_1.default.createElement("button", { className: "FileInput__file-remove", type: "button", onClick: () => removeFile(file), "aria-label": `${removeFileText} ${file.name}` }, removeFileText),
13
13
  react_1.default.createElement("span", { className: "FileInput__fileinfo" },
14
14
  showImagePreviews && file.preview && (react_1.default.createElement(react_1.default.Fragment, null,
15
15
  react_1.default.createElement("span", { className: "FileInput__preview" },
package/FileInput.d.ts CHANGED
@@ -14,7 +14,8 @@ export declare type FileInputProps = {
14
14
  */
15
15
  accept?: string | Array<string>;
16
16
  dropzoneText: string | JSX.Element;
17
- removeFileText: string;
17
+ removeFileText?: string;
18
+ lang?: string;
18
19
  showFileSize?: boolean;
19
20
  showImagePreviews?: boolean;
20
21
  FileList?: false | ((props: FileListProps) => JSX.Element | null);
@@ -34,11 +35,10 @@ export declare type FileInputProps = {
34
35
  deleted?: Array<File>;
35
36
  added?: Array<File>;
36
37
  }) => void;
38
+ onFilesRejected?: (rejectedFiles: Array<File>) => void;
37
39
  name?: string;
38
40
  value?: ReadonlyArray<File>;
39
- /**
40
- * @deprecated Use props `multiple`, `accept` instead (Will be removed in v0.11)
41
- */
41
+ /** @deprecated Use props `multiple`, `accept` instead (Will be removed in v0.11) */
42
42
  dropzoneProps?: {
43
43
  accept?: string;
44
44
  multiple?: boolean;
package/FileInput.js CHANGED
@@ -5,9 +5,23 @@ const react_1 = tslib_1.__importStar(require("react"));
5
5
  const react_dropzone_1 = require("react-dropzone"); // https://react-dropzone.js.org/#!/Dropzone
6
6
  const hooks_1 = require("@hugsmidjan/react/hooks");
7
7
  const getBemClass_1 = tslib_1.__importDefault(require("@hugsmidjan/react/utils/getBemClass"));
8
+ const i18n_1 = require("@reykjavik/hanna-utils/i18n");
8
9
  const _FileInput_utils_1 = require("./FileInput/_FileInput.utils");
9
10
  const _FileInputFileList_1 = require("./FileInput/_FileInputFileList");
10
11
  const FormField_1 = tslib_1.__importDefault(require("./FormField"));
12
+ const defaultRemoveFileText = {
13
+ is: 'Fjarlægja',
14
+ en: 'Remove',
15
+ pl: 'Usuń',
16
+ };
17
+ const defaultOnFilesRejected = (rejectedFiles) => {
18
+ window.alert('Error:\n' +
19
+ rejectedFiles
20
+ .map((elm) => {
21
+ return elm.name;
22
+ })
23
+ .join(', '));
24
+ };
11
25
  const arrayToFileList = (arr) => {
12
26
  const fileList = new DataTransfer();
13
27
  arr.forEach((item) => {
@@ -16,7 +30,7 @@ const arrayToFileList = (arr) => {
16
30
  return fileList.files;
17
31
  };
18
32
  const FileInput = (props) => {
19
- const { className, id, label, hideLabel, dropzoneProps = { multiple: true }, multiple = dropzoneProps.multiple, accept, dropzoneText, removeFileText, assistText, disabled, invalid, errorMessage, required, reqText, FileList = _FileInputFileList_1.DefaultFileList, onFilesUpdated = () => undefined, showFileSize, showImagePreviews, value = [] } = props, inputElementProps = tslib_1.__rest(props, ["className", "id", "label", "hideLabel", "dropzoneProps", "multiple", "accept", "dropzoneText", "removeFileText", "assistText", "disabled", "invalid", "errorMessage", "required", "reqText", "FileList", "onFilesUpdated", "showFileSize", "showImagePreviews", "value"]);
33
+ const { className, id, label, hideLabel, dropzoneProps = { multiple: true }, multiple = dropzoneProps.multiple, accept, dropzoneText, lang = i18n_1.DEFAULT_LANG, removeFileText = defaultRemoveFileText[lang] || defaultRemoveFileText[i18n_1.DEFAULT_LANG], assistText, disabled, invalid, errorMessage, required, reqText, FileList = _FileInputFileList_1.DefaultFileList, onFilesUpdated = () => undefined, onFilesRejected, showFileSize, showImagePreviews, value = [] } = props, inputElementProps = tslib_1.__rest(props, ["className", "id", "label", "hideLabel", "dropzoneProps", "multiple", "accept", "dropzoneText", "lang", "removeFileText", "assistText", "disabled", "invalid", "errorMessage", "required", "reqText", "FileList", "onFilesUpdated", "onFilesRejected", "showFileSize", "showImagePreviews", "value"]);
20
34
  const domid = (0, hooks_1.useDomid)(id);
21
35
  const fileInputWrapper = (0, react_1.useRef)(null);
22
36
  const fileInput = (0, react_1.useRef)(null);
@@ -32,14 +46,7 @@ const FileInput = (props) => {
32
46
  addFiles(acceptedFiles);
33
47
  setIsHover(false);
34
48
  },
35
- onDropRejected: (rejectedFiles) => {
36
- window.alert('Error:\n' +
37
- rejectedFiles
38
- .map((elm) => {
39
- return elm.name;
40
- })
41
- .join(', '));
42
- },
49
+ onDropRejected: onFilesRejected || defaultOnFilesRejected,
43
50
  onDragEnter: () => {
44
51
  // 'dragLeave' always fires right after 'dragEnter', use 'dragOver' instead
45
52
  // console.log('enter');
package/FooterInfo.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { BemPropsModifier } from '@hugsmidjan/react/types';
2
2
  export declare type FooterInfoGroup = {
3
3
  title: string;
4
- role?: JSX.IntrinsicElements['div']['role'];
5
4
  modifier?: string;
5
+ main?: boolean;
6
+ /** @deprecated (Will be removed in v0.11) */
7
+ role?: JSX.IntrinsicElements['div']['role'];
6
8
  } & BemPropsModifier & ({
7
9
  content: JSX.Element;
8
10
  html?: undefined;
package/FooterInfo.js CHANGED
@@ -5,7 +5,10 @@ const react_1 = tslib_1.__importDefault(require("react"));
5
5
  const getBemClass_1 = tslib_1.__importDefault(require("@hugsmidjan/react/utils/getBemClass"));
6
6
  const FooterInfo = (props) => {
7
7
  const { boxes } = props;
8
- return (react_1.default.createElement("div", { className: "FooterInfo" }, boxes.map((group, i) => (react_1.default.createElement("div", { className: (0, getBemClass_1.default)('FooterInfo__group', group.modifier), role: group.role, key: i },
8
+ return (react_1.default.createElement("div", { className: "FooterInfo" }, boxes.map((group, i) => (react_1.default.createElement("div", { className: (0, getBemClass_1.default)('FooterInfo__group', [
9
+ group.main && 'main',
10
+ group.modifier,
11
+ ]), key: i },
9
12
  react_1.default.createElement("h3", { className: "FooterInfo__grouptitle" }, group.title),
10
13
  group.content ? (react_1.default.createElement("div", { className: (0, getBemClass_1.default)('FooterInfo__groupcontent', group.modifier) }, group.content)) : (react_1.default.createElement("div", { className: (0, getBemClass_1.default)('FooterInfo__groupcontent', group.modifier), dangerouslySetInnerHTML: { __html: group.html } })))))));
11
14
  };
package/Heading.d.ts CHANGED
@@ -14,7 +14,8 @@ export declare type HeadingProps = {
14
14
  /**
15
15
  * Make an exception and render a `<h1/>` element.
16
16
  *
17
- * This prop is ignore if the `Tag` prop is defined. */
17
+ * This prop is ignore if the `Tag` prop is defined.
18
+ */
18
19
  forceH1?: boolean;
19
20
  } & ComponentLayoutProps;
20
21
  declare const Heading: (props: HeadingProps) => JSX.Element;
package/Heading.js CHANGED
@@ -12,7 +12,8 @@ const sizes = {
12
12
  const Heading = (props) => {
13
13
  const { size = 'normal', align, wide, children } = props;
14
14
  const Tag = props.Tag || (props.forceH1 ? 'h1' : 'h2');
15
- return (react_1.default.createElement(Tag, { className: (0, getBemClass_1.default)('Heading', [
15
+ const suppressWarning = process.env.NODE_ENV !== 'production' && Tag === 'h1' ? true : undefined;
16
+ return (react_1.default.createElement(Tag, { "data-dev-forcedH1": suppressWarning, className: (0, getBemClass_1.default)('Heading', [
16
17
  sizes[size],
17
18
  align === 'right' && 'align--' + align,
18
19
  !align && wide && 'wide',
package/IframeBlock.d.ts CHANGED
@@ -2,6 +2,8 @@ import { EitherObj } from '@reykjavik/hanna-utils';
2
2
  import { ResizerOptions } from 'iframe-resizer-react';
3
3
  export declare type IframeBlockProps = {
4
4
  src: string;
5
+ /** Accessible title attribute for the iframe (similar to alt="" on images) */
6
+ title: string;
5
7
  framed?: boolean;
6
8
  compact?: boolean;
7
9
  align?: 'right';
package/IframeBlock.js CHANGED
@@ -13,13 +13,13 @@ const iframe_resizer_react_1 = tslib_1.__importDefault(require("iframe-resizer-r
13
13
  * ```
14
14
  */
15
15
  const IframeBlock = (props) => {
16
- const { src, framed, compact, scrolling, height = 'auto', align, checkOrigin = false, } = props;
16
+ const { title, src, framed, compact, scrolling, height = 'auto', align, checkOrigin = false, } = props;
17
17
  const className = (0, getBemClass_1.default)('IframeBlock', [
18
18
  framed && 'framed',
19
19
  compact && 'compact',
20
20
  align === 'right' && 'align--' + align,
21
21
  ]);
22
- return height === 'auto' ? (react_1.default.createElement(iframe_resizer_react_1.default, { className: className, src: src, checkOrigin: checkOrigin })) : (react_1.default.createElement("iframe", { className: className, src: src,
22
+ return height === 'auto' ? (react_1.default.createElement(iframe_resizer_react_1.default, { className: className, title: title, src: src, checkOrigin: checkOrigin })) : (react_1.default.createElement("iframe", { className: className, title: title, src: src,
23
23
  // hidden tiger: pass negative height to disable iframe-resizer but not set height explicitly
24
24
  // (Silly hack, don't rely on this)
25
25
  height: height < 0 ? undefined : height,
package/ImageCards.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CardListSummaryProps, ImageCardListProps, ImageCardProps as _ImageCardProps } from './_abstract/_CardList';
2
2
  import { SeenProp } from './utils/seenEffect';
3
- /** @deprecated Use `ImageCard` instead. (Will be removed in v0.11) */
4
- export declare type ImageCardProps = _ImageCardProps;
5
3
  export declare type ImageCardsItemProps = _ImageCardProps;
4
+ /** @deprecated Use `ImageCardsItemProps` instead. (Will be removed in v0.11) */
5
+ export declare type ImageCardProps = ImageCardsItemProps;
6
6
  export declare type ImageCardsProps = ImageCardListProps & CardListSummaryProps & {
7
7
  background?: boolean;
8
8
  } & SeenProp;
package/InfoBlock.d.ts CHANGED
@@ -1,17 +1,13 @@
1
+ import { EitherObj } from '@reykjavik/hanna-utils';
1
2
  import { SeenProp } from './utils/seenEffect';
2
3
  export declare type InfoBlockProps = {
3
4
  title: string;
4
- subtitle: string | JSX.Element;
5
+ subtitle?: string | JSX.Element;
5
6
  items: Array<string | JSX.Element>;
6
- } & ({
7
- attention?: undefined;
8
- extraInfo?: undefined;
9
- } | {
10
- attention: string | JSX.Element;
11
- extraInfo?: undefined;
12
- } | {
13
- extraInfo: string | JSX.Element;
14
- attention?: undefined;
15
- }) & SeenProp;
7
+ } & EitherObj<{
8
+ attention?: string | JSX.Element;
9
+ }, {
10
+ extraInfo?: string | JSX.Element;
11
+ }> & SeenProp;
16
12
  declare const InfoBlock: (props: InfoBlockProps) => JSX.Element;
17
13
  export default InfoBlock;
package/InfoBlock.js CHANGED
@@ -8,7 +8,7 @@ const InfoBlock = (props) => {
8
8
  const [ref] = (0, seenEffect_1.useSeenEffect)(startSeen);
9
9
  return (react_1.default.createElement("div", { className: "InfoBlock", ref: ref },
10
10
  react_1.default.createElement("h2", { className: "InfoBlock__title" }, title),
11
- react_1.default.createElement("div", { className: "InfoBlock__subtitle" }, subtitle),
11
+ subtitle && react_1.default.createElement("div", { className: "InfoBlock__subtitle" }, subtitle),
12
12
  react_1.default.createElement("ul", { className: "InfoBlock__items" }, items.map((item, i) => (react_1.default.createElement("li", { key: i, className: "InfoBlock__item" }, item)))),
13
13
  'extraInfo' in props && (react_1.default.createElement("div", { className: "InfoBlock__extrainfo" }, props.extraInfo)),
14
14
  'attention' in props && (react_1.default.createElement("div", { className: "InfoBlock__attention" }, props.attention))));
package/Modal.d.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { ModalProps as _ModalProps } from '@hugsmidjan/react/Modal';
3
- export declare type ModalProps = _ModalProps & {
4
- bem?: never;
5
- bodyWrap?: never;
3
+ export declare type ModalProps = Omit<_ModalProps, 'bem' | 'bodyWrap' | 'modifier'> & {
6
4
  modifier?: 'w6' | 'w8' | 'w10';
7
5
  bling?: ReactElement;
8
6
  };
package/README.md CHANGED
@@ -32,7 +32,7 @@ automatically triggers a major version bump in this package.
32
32
 
33
33
  If you need a version of this package that "targets" an older Hanna markup
34
34
  version, you'll find the appropriate package version in the
35
- [change log](CHANGELOG.md).
35
+ [change log](https://github.com/rvk-utd/hanna/blob/main/modules/hanna-react/CHANGELOG.md).
36
36
 
37
37
  ## CSS
38
38
 
@@ -72,3 +72,8 @@ To view the documentation for older versions of Hanna, check out the
72
72
  corresponding branches in the git repo.
73
73
 
74
74
  -->
75
+
76
+ ## Changelog
77
+
78
+ See
79
+ [CHANGELOG.md](https://github.com/rvk-utd/hanna/blob/main/modules/hanna-react/CHANGELOG-lib.md)
@@ -1,9 +1,9 @@
1
1
  import { TogglerGroupFieldOptions, TogglerGroupFieldProps } from './_abstract/_TogglerGroupField';
2
2
  export declare type RadioButtonsGroupProps = TogglerGroupFieldProps & {
3
3
  value?: string;
4
- /** @deprecated (Will be removed in v0.9) */
4
+ /** @deprecated (Will be removed in v0.11) */
5
5
  columns?: '2col' | '3col';
6
- /** @deprecated (Will be removed in v0.9) */
6
+ /** @deprecated (Will be removed in v0.11) */
7
7
  layout?: 'slim';
8
8
  };
9
9
  export declare type RadioButtonsGroupOptions = TogglerGroupFieldOptions;
package/RadioGroup.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare type RadioGroupOption = TogglerGroupFieldOption;
8
8
  export declare type RadioGroupOptions = TogglerGroupFieldOptions;
9
9
  declare const RadioGroup: {
10
10
  (props: RadioGroupProps): JSX.Element;
11
+ /** @deprecated Exposed for testing purposes only. This may disappear at any time. */
11
12
  __Radio: (props: TogglerInputProps) => JSX.Element;
12
13
  };
13
14
  export default RadioGroup;
package/RadioGroup.js CHANGED
@@ -6,5 +6,6 @@ const _TogglerGroupField_1 = tslib_1.__importDefault(require("./_abstract/_Toggl
6
6
  const _TogglerInput_1 = tslib_1.__importDefault(require("./_abstract/_TogglerInput"));
7
7
  const Radio = (props) => (react_1.default.createElement(_TogglerInput_1.default, Object.assign({}, props, { bem: "Radio", type: "radio" })));
8
8
  const RadioGroup = (props) => (react_1.default.createElement(_TogglerGroupField_1.default, Object.assign({}, props, { bem: "RadioGroup", modifier: props.layout, Toggler: Radio })));
9
+ /** @deprecated Exposed for testing purposes only. This may disappear at any time. */
9
10
  RadioGroup.__Radio = Radio;
10
11
  exports.default = RadioGroup;
package/SearchInput.js CHANGED
@@ -20,6 +20,6 @@ const SearchInput = (props) => {
20
20
  return (react_1.default.createElement(FormField_1.default, { className: (0, getBemClass_1.default)('SearchInput', [], className), ssr: ssr, small: small, label: label, empty: empty, filled: filled, assistText: assistText, hideLabel: hideLabel, disabled: disabled, readOnly: readOnly, invalid: invalid, errorMessage: errorMessage, required: required, reqText: reqText, id: id, renderInput: (className, inputProps, addFocusProps) => (react_1.default.createElement("div", Object.assign({ className: className.input }, addFocusProps()),
21
21
  react_1.default.createElement("input", Object.assign({ className: "SearchInput__input", onChange: _onChange }, inputProps, inputElementProps, { ref: props.inputRef })),
22
22
  ' ',
23
- onButtonClick && (react_1.default.createElement("button", { className: "SearchInput__button", type: "button", onClick: onButtonClick, title: buttonText, ref: props.buttonRef }, buttonText)))) }));
23
+ onButtonClick && (react_1.default.createElement("button", { className: "SearchInput__button", type: "button", onClick: onButtonClick, title: buttonText, ref: props.buttonRef, disabled: disabled || readOnly }, buttonText)))) }));
24
24
  };
25
25
  exports.default = SearchInput;
package/SearchResults.js CHANGED
@@ -72,12 +72,11 @@ const SearchResults__loadmore = (props) => {
72
72
  // ===========================================================================
73
73
  const renderTitle = (props, texts) => {
74
74
  const { status, totalHits, query } = props;
75
- const lang = texts.lang || props.lang || i18n_1.DEFAULT_LANG;
76
75
  return (react_1.default.createElement("h2", { className: "SearchResults__title" },
77
76
  status === 'loadingquery'
78
77
  ? texts.loadQueryTitle
79
78
  : totalHits
80
- ? (0, prettyNum_1.prettyNum)(totalHits, { lang: lang }) +
79
+ ? (0, prettyNum_1.prettyNum)(totalHits, { lang: texts.lang }) +
81
80
  ' ' +
82
81
  texts.resultsTitle
83
82
  : texts.noResultsTitle,
package/ShareButtons.d.ts CHANGED
@@ -2,8 +2,8 @@ import { SSRSupport } from '@hugsmidjan/react/hooks';
2
2
  import { ShareButtonI18n, ShareButtonPlatforms } from '@reykjavik/hanna-utils/shareButtonsUtils';
3
3
  export declare type ShareButtonsProps = {
4
4
  ssr?: SSRSupport;
5
- children?: undefined;
6
5
  texts?: Readonly<ShareButtonI18n>;
6
+ lang?: string;
7
7
  } & Partial<Record<ShareButtonPlatforms, boolean>>;
8
8
  declare const ShareButtons: (props: ShareButtonsProps) => JSX.Element | null;
9
9
  export default ShareButtons;
package/ShareButtons.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importStar(require("react"));
5
+ const i18n_1 = require("@reykjavik/hanna-utils/i18n");
5
6
  const shareButtonsUtils_1 = require("@reykjavik/hanna-utils/shareButtonsUtils");
6
7
  const _Link_1 = require("./_abstract/_Link");
7
8
  const generateTypeList = (facebook, twitter, linkedin, email) => {
@@ -22,24 +23,28 @@ const ShareButtons__item = (props) => {
22
23
  react_1.default.createElement(_Link_1.Link, { className: 'ShareButtons__link ShareButtons__link--' + type, href: href, title: buttonText, rel: "noopener noreferrer", target: popup ? '_blank' : undefined, onClick: popup ? shareButtonsUtils_1.openInPopup : undefined }, buttonText)));
23
24
  };
24
25
  const ShareButtons = (props) => {
25
- const { texts, ssr, facebook = true, twitter = true, linkedin, email, } = props;
26
+ const { texts, lang, ssr, facebook = true, twitter = true, linkedin, email, } = props;
26
27
  const [docMeta, setDocMeta] = (0, react_1.useState)();
27
28
  const href = docLoc.href; // assign to local variable to silence `react-hooks/exhaustive-deps`
28
29
  (0, react_1.useEffect)(() => {
29
30
  // FIXME: Drop dependency on _loc.href and set up proper
30
31
  // location/route monitoring event handler, with unsubscribe on unmount
31
- const { emailSubject } = texts || {};
32
- setDocMeta((0, shareButtonsUtils_1.getDocMeta)({ emailSubject }));
33
- }, [texts, href]);
32
+ setDocMeta((0, shareButtonsUtils_1.getDocMeta)({
33
+ lang,
34
+ emailSubject: texts && texts.emailSubject,
35
+ }));
36
+ }, [texts, lang, href]);
34
37
  if (!facebook && !twitter && !linkedin && !email) {
35
38
  // no place to share
36
39
  return null;
37
40
  }
38
- const txt = texts || (docMeta && shareButtonsUtils_1.i18n[docMeta.lang]) || {};
39
- const { label, buttonLabel } = txt;
41
+ const txt = texts ||
42
+ (docMeta && (shareButtonsUtils_1.shareButtonTexts[docMeta.lang] || shareButtonsUtils_1.shareButtonTexts[i18n_1.DEFAULT_LANG])) ||
43
+ {};
44
+ const { label, buttonLabel, emailSubject } = txt;
40
45
  if (!docMeta || ssr === 'ssr-only') {
41
46
  // Generate SSR markup for hanna-sprinkles to pick up on.
42
- return (react_1.default.createElement("div", { className: "ShareButtons", "data-button-types": generateTypeList(facebook, twitter, linkedin, email), "data-label": label, "data-buttonlabel": buttonLabel, "data-emailsubject": txt.emailSubject || undefined }));
47
+ return (react_1.default.createElement("div", { className: "ShareButtons", "data-button-types": generateTypeList(facebook, twitter, linkedin, email), "data-label": label, "data-buttonlabel": buttonLabel, "data-emailsubject": emailSubject || undefined }));
43
48
  }
44
49
  const showTypes = {
45
50
  facebook,
@@ -16,7 +16,7 @@ export declare type SiteSearchACI18n = {
16
16
  export declare const defaultSiteSearchACTexts: DefaultTexts<SiteSearchACI18n>;
17
17
  export declare type SiteSearchAutocompleteProps<T> = {
18
18
  suggestions: Array<T>;
19
- renderSuggestion: RenderSuggestion<T>;
19
+ renderSuggestion?: RenderSuggestion<T>;
20
20
  setSuggestions: (suggestions: Array<T>) => void;
21
21
  getSuggestionValue: (suggestion: T) => string;
22
22
  onSuggestionsFetchRequested: (request: Autosuggest.SuggestionsFetchRequestedParams) => void;
@@ -35,7 +35,7 @@ const SiteSearchAutocomplete = (props) => {
35
35
  suggestionsList: bem + '__list',
36
36
  suggestion: bem + '__item',
37
37
  suggestionHighlighted: bem + '__item--highlighted',
38
- }, focusInputOnSuggestionClick: true, suggestions: suggestions, onSuggestionsClearRequested: () => setSuggestions([]), onSuggestionsFetchRequested: onSuggestionsFetchRequested, getSuggestionValue: getSuggestionValue, onSuggestionSelected: onSuggestionSelected, onSuggestionHighlighted: onSuggestionHighlighted, renderSuggestion: renderSuggestion, containerProps: { 'aria-label': txt.label }, renderSuggestionsContainer: ({ containerProps, children }) => (react_1.default.createElement("div", Object.assign({}, containerProps, { "aria-label": txt.suggestionsLabel }), children)), inputProps: {
38
+ }, focusInputOnSuggestionClick: true, suggestions: suggestions, onSuggestionsClearRequested: () => setSuggestions([]), onSuggestionsFetchRequested: onSuggestionsFetchRequested, getSuggestionValue: getSuggestionValue, onSuggestionSelected: onSuggestionSelected, onSuggestionHighlighted: onSuggestionHighlighted, renderSuggestion: renderSuggestion || ((s) => String(s)), containerProps: { 'aria-label': txt.label }, renderSuggestionsContainer: ({ containerProps, children }) => (react_1.default.createElement("div", Object.assign({}, containerProps, { "aria-label": suggestions.length ? txt.suggestionsLabel : undefined }), children)), inputProps: {
39
39
  ref: inputRef,
40
40
  value: value,
41
41
  onChange: (_, { newValue }) => {
package/WizardLayout.d.ts CHANGED
@@ -2,8 +2,8 @@ import { ReactNode } from 'react';
2
2
  import { SSRSupport } from '@hugsmidjan/react/hooks';
3
3
  import { HannaColorTheme } from '@reykjavik/hanna-css';
4
4
  declare type WizardLayoutProps = {
5
- wizardStepper?: ReactNode;
6
- wizardFooter?: ReactNode;
5
+ wizardStepper?: ReactNode | false;
6
+ wizardFooter?: ReactNode | false;
7
7
  colorTheme?: HannaColorTheme;
8
8
  siteName?: string;
9
9
  logoLink?: string;
@@ -26,7 +26,7 @@ export declare type WizardStepperProps = {
26
26
  steps: ReadonlyArray<WizardStepperStep>;
27
27
  /** Zero-based index of the active (current) step */
28
28
  activeStep?: number;
29
- /** By default, clickable "done" steps remain clickable */
29
+ /** By default, clickable steps remain clickable once "done" */
30
30
  disableBacktrack?: boolean;
31
31
  /** By default, clickable steps after the active step are not immediately clickable */
32
32
  allowForwardSkip?: boolean;
package/WizardStepper.js CHANGED
@@ -6,7 +6,8 @@ const getBemClass_1 = tslib_1.__importDefault(require("@hugsmidjan/react/utils/g
6
6
  const WizardStepper = (props) => {
7
7
  const { steps, activeStep = -1, allowForwardSkip, disableBacktrack, onClick } = props;
8
8
  return (react_1.default.createElement("div", { className: (0, getBemClass_1.default)('WizardStepper', activeStep === -1 && 'preview') }, steps.map((step, i) => {
9
- const { label, clickable, done, neutral } = step;
9
+ const { clickable, done, neutral } = step;
10
+ const label = step.label || '…';
10
11
  const stepClass = (0, getBemClass_1.default)('WizardStepper__step', [
11
12
  (done || (done == null && i < activeStep)) && 'done',
12
13
  neutral && 'neutral',
@@ -1,4 +1,4 @@
1
- import { ReactElement } from 'react';
1
+ import { ReactElement, ReactNode } from 'react';
2
2
  import { SSRSupport } from '@hugsmidjan/react/hooks';
3
3
  import { BemProps } from '@hugsmidjan/react/types';
4
4
  import { EitherObj } from '@reykjavik/hanna-utils';
@@ -13,10 +13,17 @@ export declare type CarouselProps<I extends Record<string, unknown> = {}, P exte
13
13
  Component: (props: P extends undefined ? I : I & P) => ReactElement | null;
14
14
  ComponentProps?: P;
15
15
  }, {
16
- children: Array<ReactElement>;
16
+ children: ReactNode;
17
+ /**
18
+ * Explicit number of items contained by the `children` prop
19
+ *
20
+ * Use this when your returned child elements are wrapped in a
21
+ * `<Fragment />` or some such.
22
+ */
23
+ itemCount?: number;
17
24
  }> & SeenProp;
18
- declare type AbstractCarouselProps<I extends Record<string, unknown> = {}, P extends Record<string, unknown> | undefined = {}> = CarouselProps<I, P> & BemProps & {
25
+ declare type AbstractCarouselProps<I extends Record<string, unknown> = Record<string, unknown>, P extends Record<string, unknown> | undefined = Record<string, unknown>> = CarouselProps<I, P> & BemProps & {
19
26
  title?: string;
20
27
  };
21
- declare const AbstractCarousel: <I extends Record<string, unknown> = {}, P extends Record<string, unknown> | undefined = {}>(props: AbstractCarouselProps<I, P>) => JSX.Element | null;
28
+ declare const AbstractCarousel: <I extends Record<string, unknown> = Record<string, unknown>, P extends Record<string, unknown> | undefined = Record<string, unknown>>(props: AbstractCarouselProps<I, P>) => JSX.Element | null;
22
29
  export default AbstractCarousel;
@@ -24,9 +24,13 @@ const scrollXBy = (elm, deltaX) => {
24
24
  };
25
25
  const AbstractCarousel = (props) => {
26
26
  const { title, items = [], Component, ComponentProps, bem = 'Carousel', modifier, ssr, startSeen, } = props;
27
- const children = props.children && props.children.filter(hanna_utils_1.notNully);
27
+ const children = !props.children
28
+ ? undefined
29
+ : Array.isArray(props.children)
30
+ ? props.children.filter(hanna_utils_1.notNully)
31
+ : [props.children];
28
32
  const [leftOffset, setLeftOffset] = (0, react_1.useState)();
29
- const itemCount = (children || items).length;
33
+ const itemCount = props.itemCount || (children || items).length;
30
34
  const listRef = (0, react_1.useRef)(null);
31
35
  const [activeItem, setActiveItem] = (0, react_1.useState)(0);
32
36
  const isBrowser = (0, hooks_1.useIsBrowserSide)(ssr);
package/assets.js CHANGED
@@ -14,7 +14,7 @@ Object.defineProperty(exports, "illustrations", { enumerable: true, get: functio
14
14
  /** @deprecated Use `getCssBundleUrl` from '@reykjavik/hanna-css' instead (Will be reomved in v0.11) */
15
15
  const getCssBundleUrl = (cssTokens,
16
16
  /** If you want to pin your CSS files to a specific version */
17
- version) => (0, hanna_css_1.getCssBundleUrl)(cssTokens, { version });
17
+ version) => (0, hanna_css_1.getCssBundleUrl)(cssTokens, { version: version });
18
18
  exports.getCssBundleUrl = getCssBundleUrl;
19
19
  // ---------------------------------------------------------------------------
20
20
  // Based on "https://styles.reykjavik.is/assets/efnistakn/menu/files.json"
package/constants.d.ts CHANGED
@@ -1,39 +1,19 @@
1
+ import { EitherObj } from '@reykjavik/hanna-utils';
1
2
  /** @depcrecated import `colorFamilies` from `@reykjavik/hanna-css` instead (Will be removed in v0.11) */
2
- export declare const colorFamilies: readonly ["esja", "faxafloi", "nautholsvik", "heidmork", "ellidaardalur", "blafjoll", "sund", "rokkur", "suld"] & {
3
- readonly esja: "esja";
4
- readonly faxafloi: "faxafloi";
5
- readonly nautholsvik: "nautholsvik";
6
- readonly heidmork: "heidmork";
7
- readonly ellidaardalur: "ellidaardalur";
8
- readonly blafjoll: "blafjoll";
9
- readonly sund: "sund";
10
- readonly rokkur: "rokkur";
11
- readonly suld: "suld";
12
- } & {
3
+ export declare const colorFamilies: readonly ["esja", "faxafloi", "nautholsvik", "heidmork", "ellidaardalur", "blafjoll", "sund", "rokkur", "suld"] & Readonly<Record<import("@reykjavik/hanna-css").ColorFamily, import("@reykjavik/hanna-css").ColorFamily>> & {
13
4
  /** @deprecated This is a typo (Will be removed in v0.11) */
14
5
  ellidarardalur: string;
15
6
  };
16
7
  /** @depcrecated import type `ColorFamily` from `@reykjavik/hanna-css` instead (Will be removed in v0.11) */
17
8
  export type { ColorFamily } from '@reykjavik/hanna-css';
18
9
  /** @depcrecated import `colorThemes` from `@reykjavik/hanna-css` instead (Will be removed in v0.11) */
19
- export declare const themeOptions: readonly ["trustworthy", "dependable", "friendly", "lively", "colorful"] & {
20
- readonly trustworthy: "trustworthy";
21
- readonly dependable: "dependable";
22
- readonly friendly: "friendly";
23
- readonly lively: "lively";
24
- readonly colorful: "colorful";
25
- };
10
+ export declare const themeOptions: readonly ["trustworthy", "dependable", "friendly", "lively", "colorful"] & Readonly<Record<import("@reykjavik/hanna-css").HannaColorTheme, import("@reykjavik/hanna-css").HannaColorTheme>>;
26
11
  /** @depcrecated import type `HannaColorTheme` from `@reykjavik/hanna-css` instead (Will be removed in v0.11) */
27
12
  export type { HannaColorTheme as ThemeOption } from '@reykjavik/hanna-css';
28
13
  export declare type Alignment = 'right' | 'left';
29
14
  export declare const aligns: Record<string, true | undefined>;
30
- export declare type ComponentLayoutProps<Align extends string = 'right'> = {
31
- wide?: undefined;
32
- align?: undefined;
33
- } | {
34
- wide: boolean;
35
- align?: undefined;
36
- } | {
37
- wide?: undefined;
38
- align: Align;
39
- };
15
+ export declare type ComponentLayoutProps<Align extends string = 'right'> = EitherObj<{
16
+ wide?: boolean;
17
+ }, {
18
+ align?: Align;
19
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/hanna-react",
3
- "version": "0.10.70",
3
+ "version": "0.10.71",
4
4
  "author": "Reykjavík (http://www.reykjavik.is)",
5
5
  "contributors": [
6
6
  "Hugsmiðjan ehf (http://www.hugsmidjan.is)",
@@ -15,8 +15,8 @@
15
15
  "dependencies": {
16
16
  "@hugsmidjan/qj": "^4.10.2",
17
17
  "@hugsmidjan/react": "^0.4.17",
18
- "@reykjavik/hanna-css": "^0.3.7",
19
- "@reykjavik/hanna-utils": "^0.1.14",
18
+ "@reykjavik/hanna-css": "^0.3.10",
19
+ "@reykjavik/hanna-utils": "^0.1.17",
20
20
  "@types/react": "^17.0.24",
21
21
  "@types/react-autosuggest": "^10.1.0",
22
22
  "@types/react-datepicker": "^3.0.2",