@reykjavik/hanna-react 0.10.170 → 0.10.172

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
@@ -4,6 +4,24 @@
4
4
 
5
5
  - ... <!-- Add new lines here. -->
6
6
 
7
+ ## 0.10.172
8
+
9
+ _2026-04-30_
10
+
11
+ - `Datepicker`:
12
+ - feat: Scroll calendar into view when opened, and back to input when closed
13
+
14
+ ## 0.10.171
15
+
16
+ _2026-04-02_
17
+
18
+ - feat: Add component `StatusTag`
19
+ - feat: Add component `Timeline`
20
+ - `utils`:
21
+ - feat: Deprecate `domid` in favor of `dumbId` from `@reykjavik/hanna-utils`
22
+ - fix: Update className selector for `MobileMenuToggler` button in
23
+ `useHannaUIState()`
24
+
7
25
  ## 0.10.170
8
26
 
9
27
  _2026-03-10_
package/Datepicker.d.ts CHANGED
@@ -12,7 +12,7 @@ export type DatepickerProps = {
12
12
  * the `<input/>` element is still `type="text"` and it's `.value` is
13
13
  * the human-readable (parsed) date `string`.
14
14
  *
15
- * Use this incombination with the `isoMode` prop to submit ISO-8601
15
+ * Use this in combination with the `isoMode` prop to submit ISO-8601
16
16
  * formatted input values
17
17
  */
18
18
  defaultValue?: Date;
package/Datepicker.js CHANGED
@@ -154,13 +154,16 @@ const Datepicker = (props) => {
154
154
  .concat(txts.dateFormats)
155
155
  .concat(['P', 'PP', 'PPP']);
156
156
  }, [dateFormat, txts]);
157
+ const wrapperRef = (0, react_1.useRef)();
157
158
  return (react_1.default.createElement(FormField_js_1.FormField, Object.assign({ extraClassName: "Datepicker", filled: filled, empty: empty }, fieldWrapperProps, { renderInput: (className, inputProps, addFocusProps) => {
158
- return (react_1.default.createElement("div", Object.assign({ className: className.input, onClick: ({ target, currentTarget }) => { var _a; return target === currentTarget && ((_a = currentTarget.querySelector('input')) === null || _a === void 0 ? void 0 : _a.focus()); }, ref: inputRef &&
159
- ((elm) => {
159
+ return (react_1.default.createElement("div", Object.assign({ className: className.input, onClick: ({ target, currentTarget }) => { var _a; return target === currentTarget && ((_a = currentTarget.querySelector('input')) === null || _a === void 0 ? void 0 : _a.focus()); }, ref: (elm) => {
160
+ wrapperRef.current = elm;
161
+ if (inputRef) {
160
162
  inputRef.current =
161
163
  (elm === null || elm === void 0 ? void 0 : elm.querySelector('input')) || undefined;
162
- return elm;
163
- }) }, addFocusProps()),
164
+ }
165
+ return elm;
166
+ } }, addFocusProps()),
164
167
  isoMode && react_1.default.createElement("input", { type: "hidden", name: name, value: toLocalIsoDate(value) }),
165
168
  react_1.default.createElement(ReactDatepicker_js_1.ReactDatePicker, Object.assign({ required: inputProps.required, disabled: inputProps.disabled, readOnly: inputProps.readOnly, selected: value, name: isoMode ? undefined : name, locale: lang || i18n_1.DEFAULT_LANG, dateFormat: normalizedDateFormats, onChange: (date) => {
166
169
  date = date || undefined;
@@ -173,7 +176,17 @@ const Datepicker = (props) => {
173
176
  }, placeholderText: placeholder,
174
177
  // TODO: Implement this
175
178
  // selectsRange
176
- minDate: minDateNormalized, maxDate: maxDate, startDate: startDate, endDate: endDate, selectsStart: isStartDate, selectsEnd: isEndDate, formatWeekDay: (weekday) => weekday.charAt(0).toUpperCase(), showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, showMonthDropdown: true }, inputProps, txts, datepickerExtraProps, { autoComplete: "off" }))));
179
+ minDate: minDateNormalized, maxDate: maxDate, startDate: startDate, endDate: endDate, selectsStart: isStartDate, selectsEnd: isEndDate, formatWeekDay: (weekday) => weekday.charAt(0).toUpperCase(), showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, onCalendarOpen: () => {
180
+ setTimeout(() => {
181
+ var _a;
182
+ const calElm = (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('.react-datepicker');
183
+ calElm === null || calElm === void 0 ? void 0 : calElm.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
184
+ }, 100);
185
+ }, onCalendarClose: () => {
186
+ var _a;
187
+ const inputElm = (inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) || ((_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input'));
188
+ inputElm === null || inputElm === void 0 ? void 0 : inputElm.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
189
+ }, showMonthDropdown: true }, inputProps, txts, datepickerExtraProps, { autoComplete: "off" }))));
177
190
  } })));
178
191
  };
179
192
  exports.Datepicker = Datepicker;
@@ -10,7 +10,7 @@ const htmlClass = (className, add) => {
10
10
  const noop = () => undefined;
11
11
  const HamburgerMedias = { phone: 1, phablet: 1, tablet: 1 };
12
12
  const useMobileMenuToggling = (opts) => {
13
- const { doInitialize, togglerElm = '.MainMenuToggler' } = typeof opts === 'boolean'
13
+ const { doInitialize, togglerElm = '.MainMenuToggler, .MobileMenuToggler' } = typeof opts === 'boolean'
14
14
  ? ({ doInitialize: opts })
15
15
  : !opts
16
16
  ? ({ doInitialize: true })
package/StatusTag.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { ReactNode } from 'react';
2
+ import { WrapperElmProps } from './utils.js';
3
+ declare const colors: {
4
+ readonly none: undefined;
5
+ readonly blue: "color--blue";
6
+ readonly green: "color--green";
7
+ readonly yellow: "color--yellow";
8
+ readonly red: "color--red";
9
+ };
10
+ export type StatusTagColor = keyof typeof colors;
11
+ export type StatusTagProps = {
12
+ /** Label takes preference over `children` */
13
+ label?: ReactNode;
14
+ /** Default: 'none' (grey) */
15
+ color?: StatusTagColor;
16
+ /** Hides/removes the colored indicator light ball/bulp. */
17
+ light?: 'off';
18
+ /** Make the status tag larger. Defaults to false. */
19
+ large?: boolean;
20
+ children?: ReactNode;
21
+ } & WrapperElmProps<'span', 'children'>;
22
+ export declare const StatusTag: (props: StatusTagProps) => JSX.Element;
23
+ export {};
package/StatusTag.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatusTag = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const hanna_utils_1 = require("@reykjavik/hanna-utils");
7
+ const colors = {
8
+ none: undefined,
9
+ blue: 'color--blue',
10
+ green: 'color--green',
11
+ yellow: 'color--yellow',
12
+ red: 'color--red',
13
+ };
14
+ const StatusTag = (props) => {
15
+ const { children, label, color, light, large, wrapperProps } = props;
16
+ return (react_1.default.createElement("span", Object.assign({}, wrapperProps, { className: (0, hanna_utils_1.modifiedClass)('StatusTag', [colors[color || 'none'], large && 'large', light === 'off' && 'light--off'], (wrapperProps || {}).className) }),
17
+ react_1.default.createElement("span", { className: "StatusTag__label" }, label || children)));
18
+ };
19
+ exports.StatusTag = StatusTag;
package/Timeline.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { TagPillColor } from '@reykjavik/hanna-react/TagPill';
2
+ import { HannaLang } from '@reykjavik/hanna-utils/i18n';
3
+ export type TimeLineItem = {
4
+ /** The main timeline item value */
5
+ title: string;
6
+ /** Flexible categorization field. Could for example contain a person/user's name */
7
+ category?: string;
8
+ /** More details about the */
9
+ description?: string;
10
+ /**
11
+ * The date/time of the timeline event.
12
+ *
13
+ * `Date` and `number` (timestamp) values are auto formatted according to the
14
+ * currently active `HannaLang`. If you need a non-default format pass it as a
15
+ * preformatted string.
16
+ */
17
+ date?: Date | number | string;
18
+ /** Displays a status tag next to the timeline item. */
19
+ status?: {
20
+ label: string;
21
+ color?: TagPillColor;
22
+ };
23
+ /**
24
+ * If no item is marked current, then the first item in the array is impilicitly the current one.
25
+ *
26
+ * If multiple items are marked current, then the first one is the current one.
27
+ */
28
+ current?: boolean;
29
+ } | 'loading';
30
+ export type TimelineProps = {
31
+ /** Optional title to show above the timeline. */
32
+ title?: string;
33
+ /** The items to display in the timeline. */
34
+ items: Array<TimeLineItem>;
35
+ /**
36
+ * If true, Item `Dates` will be formatted year, month day only, without the
37
+ * time of day (hours and minutes) visible.
38
+ *
39
+ * Default: `false`
40
+ */
41
+ hideTime?: boolean;
42
+ /** If true, the timeline will be sorted with the oldest item first. By default, the newest item is first. */
43
+ oldestFirst?: boolean;
44
+ /** Defaults to the current global `DEFAULT_LANG` */
45
+ lang?: HannaLang;
46
+ };
47
+ export declare const Timeline: (props: TimelineProps) => JSX.Element;
package/Timeline.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Timeline = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const Skeleton_1 = require("@reykjavik/hanna-react/Skeleton");
7
+ const TagPill_1 = require("@reykjavik/hanna-react/TagPill");
8
+ const hanna_utils_1 = require("@reykjavik/hanna-utils");
9
+ const i18n_1 = require("@reykjavik/hanna-utils/i18n");
10
+ const dateFormatters = {};
11
+ const dateTimeFormatters = {};
12
+ const getDateFormatter = (lang, hideTime) => hideTime
13
+ ? dateFormatters[lang] ||
14
+ (dateFormatters[lang] = new Intl.DateTimeFormat(lang, {
15
+ year: 'numeric',
16
+ month: 'long',
17
+ day: 'numeric',
18
+ }))
19
+ : dateTimeFormatters[lang] ||
20
+ (dateTimeFormatters[lang] = new Intl.DateTimeFormat(lang, {
21
+ year: 'numeric',
22
+ month: 'long',
23
+ day: 'numeric',
24
+ hour: '2-digit',
25
+ minute: '2-digit',
26
+ }));
27
+ const Timeline = (props) => {
28
+ const { title, items, oldestFirst, lang = i18n_1.DEFAULT_LANG, hideTime } = props;
29
+ const dateFmt = getDateFormatter(lang, hideTime);
30
+ const currentIdx = Math.max(items.findIndex((item) => item !== 'loading' && !!item.current), 0);
31
+ return (react_1.default.createElement("div", { className: (0, hanna_utils_1.modifiedClass)('Timeline', [oldestFirst && 'oldestFirst']) },
32
+ title && react_1.default.createElement("h3", { className: "Timeline__title" }, title),
33
+ react_1.default.createElement("ul", { className: "Timeline__items" }, items.map((item, i) => {
34
+ if (item === 'loading') {
35
+ return (react_1.default.createElement("li", { key: i, className: "Timeline__item Timeline__item--loading" },
36
+ react_1.default.createElement(Skeleton_1.Skeleton, { height: 1, wrapperProps: { className: 'Skeleton__circle' } }),
37
+ react_1.default.createElement(Skeleton_1.Skeleton, { items: 1, height: 3, text: true })));
38
+ }
39
+ const { title, category: author, description, date, status } = item;
40
+ return (react_1.default.createElement("li", { key: i, className: (0, hanna_utils_1.modifiedClass)('Timeline__item', [
41
+ i < currentIdx && 'future',
42
+ i > currentIdx && 'past',
43
+ ]), "aria-current": currentIdx === i ? 'step' : undefined },
44
+ react_1.default.createElement("strong", { className: "Timeline__item__title" }, title),
45
+ status && react_1.default.createElement(TagPill_1.TagPill, { color: status.color }, status.label),
46
+ author && react_1.default.createElement("div", { className: "Timeline__item__category" }, author),
47
+ description && (react_1.default.createElement("div", { className: "Timeline__item__description" }, description)),
48
+ date && (react_1.default.createElement("div", { className: "Timeline__item__date" }, typeof date === 'string' ? date : dateFmt.format(date)))));
49
+ }))));
50
+ };
51
+ exports.Timeline = Timeline;
@@ -12,7 +12,7 @@ export type DatepickerProps = {
12
12
  * the `<input/>` element is still `type="text"` and it's `.value` is
13
13
  * the human-readable (parsed) date `string`.
14
14
  *
15
- * Use this incombination with the `isoMode` prop to submit ISO-8601
15
+ * Use this in combination with the `isoMode` prop to submit ISO-8601
16
16
  * formatted input values
17
17
  */
18
18
  defaultValue?: Date;
package/esm/Datepicker.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from 'react';
1
+ import React, { useMemo, useRef } from 'react';
2
2
  import { DEFAULT_LANG, getTexts, } from '@reykjavik/hanna-utils/i18n';
3
3
  // For more info on localization see: https://stackoverflow.com/questions/54399084/change-locale-in-react-datepicker/58306958#58306958
4
4
  import is from 'date-fns/locale/is/index.js';
@@ -149,13 +149,16 @@ export const Datepicker = (props) => {
149
149
  .concat(txts.dateFormats)
150
150
  .concat(['P', 'PP', 'PPP']);
151
151
  }, [dateFormat, txts]);
152
+ const wrapperRef = useRef();
152
153
  return (React.createElement(FormField, Object.assign({ extraClassName: "Datepicker", filled: filled, empty: empty }, fieldWrapperProps, { renderInput: (className, inputProps, addFocusProps) => {
153
- return (React.createElement("div", Object.assign({ className: className.input, onClick: ({ target, currentTarget }) => { var _a; return target === currentTarget && ((_a = currentTarget.querySelector('input')) === null || _a === void 0 ? void 0 : _a.focus()); }, ref: inputRef &&
154
- ((elm) => {
154
+ return (React.createElement("div", Object.assign({ className: className.input, onClick: ({ target, currentTarget }) => { var _a; return target === currentTarget && ((_a = currentTarget.querySelector('input')) === null || _a === void 0 ? void 0 : _a.focus()); }, ref: (elm) => {
155
+ wrapperRef.current = elm;
156
+ if (inputRef) {
155
157
  inputRef.current =
156
158
  (elm === null || elm === void 0 ? void 0 : elm.querySelector('input')) || undefined;
157
- return elm;
158
- }) }, addFocusProps()),
159
+ }
160
+ return elm;
161
+ } }, addFocusProps()),
159
162
  isoMode && React.createElement("input", { type: "hidden", name: name, value: toLocalIsoDate(value) }),
160
163
  React.createElement(ReactDatePicker, Object.assign({ required: inputProps.required, disabled: inputProps.disabled, readOnly: inputProps.readOnly, selected: value, name: isoMode ? undefined : name, locale: lang || DEFAULT_LANG, dateFormat: normalizedDateFormats, onChange: (date) => {
161
164
  date = date || undefined;
@@ -168,7 +171,17 @@ export const Datepicker = (props) => {
168
171
  }, placeholderText: placeholder,
169
172
  // TODO: Implement this
170
173
  // selectsRange
171
- minDate: minDateNormalized, maxDate: maxDate, startDate: startDate, endDate: endDate, selectsStart: isStartDate, selectsEnd: isEndDate, formatWeekDay: (weekday) => weekday.charAt(0).toUpperCase(), showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, showMonthDropdown: true }, inputProps, txts, datepickerExtraProps, { autoComplete: "off" }))));
174
+ minDate: minDateNormalized, maxDate: maxDate, startDate: startDate, endDate: endDate, selectsStart: isStartDate, selectsEnd: isEndDate, formatWeekDay: (weekday) => weekday.charAt(0).toUpperCase(), showYearDropdown: true, scrollableYearDropdown: true, yearDropdownItemNumber: 15, onCalendarOpen: () => {
175
+ setTimeout(() => {
176
+ var _a;
177
+ const calElm = (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('.react-datepicker');
178
+ calElm === null || calElm === void 0 ? void 0 : calElm.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
179
+ }, 100);
180
+ }, onCalendarClose: () => {
181
+ var _a;
182
+ const inputElm = (inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) || ((_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input'));
183
+ inputElm === null || inputElm === void 0 ? void 0 : inputElm.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
184
+ }, showMonthDropdown: true }, inputProps, txts, datepickerExtraProps, { autoComplete: "off" }))));
172
185
  } })));
173
186
  };
174
187
  export default Datepicker;
@@ -7,7 +7,7 @@ const htmlClass = (className, add) => {
7
7
  const noop = () => undefined;
8
8
  const HamburgerMedias = { phone: 1, phablet: 1, tablet: 1 };
9
9
  export const useMobileMenuToggling = (opts) => {
10
- const { doInitialize, togglerElm = '.MainMenuToggler' } = typeof opts === 'boolean'
10
+ const { doInitialize, togglerElm = '.MainMenuToggler, .MobileMenuToggler' } = typeof opts === 'boolean'
11
11
  ? ({ doInitialize: opts })
12
12
  : !opts
13
13
  ? ({ doInitialize: true })
@@ -0,0 +1,23 @@
1
+ import { ReactNode } from 'react';
2
+ import { WrapperElmProps } from './utils.js';
3
+ declare const colors: {
4
+ readonly none: undefined;
5
+ readonly blue: "color--blue";
6
+ readonly green: "color--green";
7
+ readonly yellow: "color--yellow";
8
+ readonly red: "color--red";
9
+ };
10
+ export type StatusTagColor = keyof typeof colors;
11
+ export type StatusTagProps = {
12
+ /** Label takes preference over `children` */
13
+ label?: ReactNode;
14
+ /** Default: 'none' (grey) */
15
+ color?: StatusTagColor;
16
+ /** Hides/removes the colored indicator light ball/bulp. */
17
+ light?: 'off';
18
+ /** Make the status tag larger. Defaults to false. */
19
+ large?: boolean;
20
+ children?: ReactNode;
21
+ } & WrapperElmProps<'span', 'children'>;
22
+ export declare const StatusTag: (props: StatusTagProps) => JSX.Element;
23
+ export {};
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { modifiedClass } from '@reykjavik/hanna-utils';
3
+ const colors = {
4
+ none: undefined,
5
+ blue: 'color--blue',
6
+ green: 'color--green',
7
+ yellow: 'color--yellow',
8
+ red: 'color--red',
9
+ };
10
+ export const StatusTag = (props) => {
11
+ const { children, label, color, light, large, wrapperProps } = props;
12
+ return (React.createElement("span", Object.assign({}, wrapperProps, { className: modifiedClass('StatusTag', [colors[color || 'none'], large && 'large', light === 'off' && 'light--off'], (wrapperProps || {}).className) }),
13
+ React.createElement("span", { className: "StatusTag__label" }, label || children)));
14
+ };
@@ -0,0 +1,47 @@
1
+ import { TagPillColor } from '@reykjavik/hanna-react/TagPill';
2
+ import { HannaLang } from '@reykjavik/hanna-utils/i18n';
3
+ export type TimeLineItem = {
4
+ /** The main timeline item value */
5
+ title: string;
6
+ /** Flexible categorization field. Could for example contain a person/user's name */
7
+ category?: string;
8
+ /** More details about the */
9
+ description?: string;
10
+ /**
11
+ * The date/time of the timeline event.
12
+ *
13
+ * `Date` and `number` (timestamp) values are auto formatted according to the
14
+ * currently active `HannaLang`. If you need a non-default format pass it as a
15
+ * preformatted string.
16
+ */
17
+ date?: Date | number | string;
18
+ /** Displays a status tag next to the timeline item. */
19
+ status?: {
20
+ label: string;
21
+ color?: TagPillColor;
22
+ };
23
+ /**
24
+ * If no item is marked current, then the first item in the array is impilicitly the current one.
25
+ *
26
+ * If multiple items are marked current, then the first one is the current one.
27
+ */
28
+ current?: boolean;
29
+ } | 'loading';
30
+ export type TimelineProps = {
31
+ /** Optional title to show above the timeline. */
32
+ title?: string;
33
+ /** The items to display in the timeline. */
34
+ items: Array<TimeLineItem>;
35
+ /**
36
+ * If true, Item `Dates` will be formatted year, month day only, without the
37
+ * time of day (hours and minutes) visible.
38
+ *
39
+ * Default: `false`
40
+ */
41
+ hideTime?: boolean;
42
+ /** If true, the timeline will be sorted with the oldest item first. By default, the newest item is first. */
43
+ oldestFirst?: boolean;
44
+ /** Defaults to the current global `DEFAULT_LANG` */
45
+ lang?: HannaLang;
46
+ };
47
+ export declare const Timeline: (props: TimelineProps) => JSX.Element;
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { Skeleton } from '@reykjavik/hanna-react/Skeleton';
3
+ import { TagPill } from '@reykjavik/hanna-react/TagPill';
4
+ import { modifiedClass } from '@reykjavik/hanna-utils';
5
+ import { DEFAULT_LANG } from '@reykjavik/hanna-utils/i18n';
6
+ const dateFormatters = {};
7
+ const dateTimeFormatters = {};
8
+ const getDateFormatter = (lang, hideTime) => hideTime
9
+ ? dateFormatters[lang] ||
10
+ (dateFormatters[lang] = new Intl.DateTimeFormat(lang, {
11
+ year: 'numeric',
12
+ month: 'long',
13
+ day: 'numeric',
14
+ }))
15
+ : dateTimeFormatters[lang] ||
16
+ (dateTimeFormatters[lang] = new Intl.DateTimeFormat(lang, {
17
+ year: 'numeric',
18
+ month: 'long',
19
+ day: 'numeric',
20
+ hour: '2-digit',
21
+ minute: '2-digit',
22
+ }));
23
+ export const Timeline = (props) => {
24
+ const { title, items, oldestFirst, lang = DEFAULT_LANG, hideTime } = props;
25
+ const dateFmt = getDateFormatter(lang, hideTime);
26
+ const currentIdx = Math.max(items.findIndex((item) => item !== 'loading' && !!item.current), 0);
27
+ return (React.createElement("div", { className: modifiedClass('Timeline', [oldestFirst && 'oldestFirst']) },
28
+ title && React.createElement("h3", { className: "Timeline__title" }, title),
29
+ React.createElement("ul", { className: "Timeline__items" }, items.map((item, i) => {
30
+ if (item === 'loading') {
31
+ return (React.createElement("li", { key: i, className: "Timeline__item Timeline__item--loading" },
32
+ React.createElement(Skeleton, { height: 1, wrapperProps: { className: 'Skeleton__circle' } }),
33
+ React.createElement(Skeleton, { items: 1, height: 3, text: true })));
34
+ }
35
+ const { title, category: author, description, date, status } = item;
36
+ return (React.createElement("li", { key: i, className: modifiedClass('Timeline__item', [
37
+ i < currentIdx && 'future',
38
+ i > currentIdx && 'past',
39
+ ]), "aria-current": currentIdx === i ? 'step' : undefined },
40
+ React.createElement("strong", { className: "Timeline__item__title" }, title),
41
+ status && React.createElement(TagPill, { color: status.color }, status.label),
42
+ author && React.createElement("div", { className: "Timeline__item__category" }, author),
43
+ description && (React.createElement("div", { className: "Timeline__item__description" }, description)),
44
+ date && (React.createElement("div", { className: "Timeline__item__date" }, typeof date === 'string' ? date : dateFmt.format(date)))));
45
+ }))));
46
+ };
package/esm/index.d.ts CHANGED
@@ -8,12 +8,14 @@
8
8
  /// <reference path="./VerticalTabsTOC.d.tsx" />
9
9
  /// <reference path="./VSpacer.d.tsx" />
10
10
  /// <reference path="./Tooltip.d.tsx" />
11
+ /// <reference path="./Timeline.d.tsx" />
11
12
  /// <reference path="./TextInput.d.tsx" />
12
13
  /// <reference path="./TextButton.d.tsx" />
13
14
  /// <reference path="./TextBlock.d.tsx" />
14
15
  /// <reference path="./TagPill.d.tsx" />
15
16
  /// <reference path="./Tabs.d.tsx" />
16
17
  /// <reference path="./SubHeading.d.tsx" />
18
+ /// <reference path="./StatusTag.d.tsx" />
17
19
  /// <reference path="./Skeleton.d.tsx" />
18
20
  /// <reference path="./SiteSearchInput.d.tsx" />
19
21
  /// <reference path="./SiteSearchCurtain.d.tsx" />
@@ -1,7 +1,3 @@
1
- /**
2
- * Returns a short locally-unique ID string.
3
- */
4
- export declare const domid: () => string;
5
1
  /**
6
2
  * Returns a stable, unique ID string.
7
3
  *
@@ -14,3 +10,5 @@ export declare const domid: () => string;
14
10
  * mode and there's nothing we can do about it, except to ignore them.)
15
11
  */
16
12
  export declare const useDomid: (staticId?: string) => string;
13
+ /** @deprecated Use `import { dumbId } from '@reykjavik/hanna-utils'` instead (Will be removed in v0.3) */
14
+ export declare const domid: () => string;
@@ -1,12 +1,7 @@
1
1
  import React from 'react';
2
+ import { dumbId } from '@reykjavik/hanna-utils';
2
3
  // @ts-expect-error (transparently feature-detect useId hook, which is introduced in React@18)
3
4
  const useId = React.useId;
4
- const domid_prefix = `_${ /*@__PURE__*/`${Date.now()}-`.slice(6)}`;
5
- let domid_incr = 0;
6
- /**
7
- * Returns a short locally-unique ID string.
8
- */
9
- export const domid = () => domid_prefix + domid_incr++;
10
5
  /**
11
6
  * Returns a stable, unique ID string.
12
7
  *
@@ -26,7 +21,9 @@ export const useDomid = useId
26
21
  : (staticId) => {
27
22
  const idRef = React.useRef();
28
23
  if (!idRef.current) {
29
- idRef.current = staticId || domid();
24
+ idRef.current = staticId || dumbId();
30
25
  }
31
26
  return idRef.current;
32
27
  };
28
+ /** @deprecated Use `import { dumbId } from '@reykjavik/hanna-utils'` instead (Will be removed in v0.3) */
29
+ export const domid = dumbId;
package/index.d.ts CHANGED
@@ -8,12 +8,14 @@
8
8
  /// <reference path="./VerticalTabsTOC.d.tsx" />
9
9
  /// <reference path="./VSpacer.d.tsx" />
10
10
  /// <reference path="./Tooltip.d.tsx" />
11
+ /// <reference path="./Timeline.d.tsx" />
11
12
  /// <reference path="./TextInput.d.tsx" />
12
13
  /// <reference path="./TextButton.d.tsx" />
13
14
  /// <reference path="./TextBlock.d.tsx" />
14
15
  /// <reference path="./TagPill.d.tsx" />
15
16
  /// <reference path="./Tabs.d.tsx" />
16
17
  /// <reference path="./SubHeading.d.tsx" />
18
+ /// <reference path="./StatusTag.d.tsx" />
17
19
  /// <reference path="./Skeleton.d.tsx" />
18
20
  /// <reference path="./SiteSearchInput.d.tsx" />
19
21
  /// <reference path="./SiteSearchCurtain.d.tsx" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/hanna-react",
3
- "version": "0.10.170",
3
+ "version": "0.10.172",
4
4
  "author": "Reykjavík (http://www.reykjavik.is)",
5
5
  "contributors": [
6
6
  "Hugsmiðjan ehf (http://www.hugsmidjan.is)",
@@ -17,8 +17,8 @@
17
17
  "@floating-ui/react": "^0.19.2",
18
18
  "@hugsmidjan/qj": "^4.22.1",
19
19
  "@hugsmidjan/react": "^0.4.32",
20
- "@reykjavik/hanna-css": "^0.4.26",
21
- "@reykjavik/hanna-utils": "^0.2.21",
20
+ "@reykjavik/hanna-css": "^0.4.27",
21
+ "@reykjavik/hanna-utils": "^0.2.22",
22
22
  "@types/react-autosuggest": "^10.1.0",
23
23
  "@types/react-datepicker": "^4.8.0",
24
24
  "@types/react-transition-group": "^4.4.0",
@@ -85,6 +85,10 @@
85
85
  "import": "./esm/Tooltip.js",
86
86
  "require": "./Tooltip.js"
87
87
  },
88
+ "./Timeline": {
89
+ "import": "./esm/Timeline.js",
90
+ "require": "./Timeline.js"
91
+ },
88
92
  "./TextInput": {
89
93
  "import": "./esm/TextInput.js",
90
94
  "require": "./TextInput.js"
@@ -109,6 +113,10 @@
109
113
  "import": "./esm/SubHeading.js",
110
114
  "require": "./SubHeading.js"
111
115
  },
116
+ "./StatusTag": {
117
+ "import": "./esm/StatusTag.js",
118
+ "require": "./StatusTag.js"
119
+ },
112
120
  "./Skeleton": {
113
121
  "import": "./esm/Skeleton.js",
114
122
  "require": "./Skeleton.js"
@@ -1,7 +1,3 @@
1
- /**
2
- * Returns a short locally-unique ID string.
3
- */
4
- export declare const domid: () => string;
5
1
  /**
6
2
  * Returns a stable, unique ID string.
7
3
  *
@@ -14,3 +10,5 @@ export declare const domid: () => string;
14
10
  * mode and there's nothing we can do about it, except to ignore them.)
15
11
  */
16
12
  export declare const useDomid: (staticId?: string) => string;
13
+ /** @deprecated Use `import { dumbId } from '@reykjavik/hanna-utils'` instead (Will be removed in v0.3) */
14
+ export declare const domid: () => string;
package/utils/useDomid.js CHANGED
@@ -1,17 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useDomid = exports.domid = void 0;
3
+ exports.domid = exports.useDomid = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
+ const hanna_utils_1 = require("@reykjavik/hanna-utils");
6
7
  // @ts-expect-error (transparently feature-detect useId hook, which is introduced in React@18)
7
8
  const useId = react_1.default.useId;
8
- const domid_prefix = `_${ /*@__PURE__*/`${Date.now()}-`.slice(6)}`;
9
- let domid_incr = 0;
10
- /**
11
- * Returns a short locally-unique ID string.
12
- */
13
- const domid = () => domid_prefix + domid_incr++;
14
- exports.domid = domid;
15
9
  /**
16
10
  * Returns a stable, unique ID string.
17
11
  *
@@ -31,7 +25,9 @@ exports.useDomid = useId
31
25
  : (staticId) => {
32
26
  const idRef = react_1.default.useRef();
33
27
  if (!idRef.current) {
34
- idRef.current = staticId || (0, exports.domid)();
28
+ idRef.current = staticId || (0, hanna_utils_1.dumbId)();
35
29
  }
36
30
  return idRef.current;
37
31
  };
32
+ /** @deprecated Use `import { dumbId } from '@reykjavik/hanna-utils'` instead (Will be removed in v0.3) */
33
+ exports.domid = hanna_utils_1.dumbId;