@reykjavik/hanna-react 0.10.133 → 0.10.135

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.135
8
+
9
+ _2024-09-03_
10
+
11
+ - feat: Add prop `variant="light"` to `MainMenu2`
12
+
13
+ ## 0.10.134
14
+
15
+ _2024-08-19_
16
+
17
+ - `MainÞMenu2`:
18
+ - feat: Pass `openMenu()` prop to `MainMenu2CustomItem` callbacks
19
+ - feat: Allow rich-text (JSX) `label`s for menu items
20
+ - feat: Allow `icon` prop on related items
21
+ - fix: links with empty-string `href` not rendered server-side
22
+ - `MainMenu`:
23
+ - fix: Unnecessary scroll-reset when resizing window to enter hamburger-mode
24
+
7
25
  ## 0.10.133
8
26
 
9
27
  _2024-08-08_
package/MainMenu.js CHANGED
@@ -108,8 +108,11 @@ const _MainMenu = (props) => {
108
108
  const htmlElmDataset = htmlElm.dataset;
109
109
  // const menuElm = menuElmRef.current as HTMLElement;
110
110
  _setActivePanel((activePanel) => {
111
+ if (!newActive && !activePanel) {
112
+ return undefined;
113
+ }
111
114
  if (!newActive) {
112
- activePanel && setLaggyActivePanel(activePanel, 1000);
115
+ setLaggyActivePanel(activePanel, 1000);
113
116
  htmlElm.scrollTop = parseInt(htmlElmDataset.scrollTop || '') || 0;
114
117
  delete htmlElmDataset.scrollTop;
115
118
  delete htmlElmDataset.megaPanelActive;
package/MainMenu2.d.ts CHANGED
@@ -16,7 +16,7 @@ export type MainMenu2I18n = {
16
16
  export declare const defaultMainMenu2Texts: DefaultTexts<MainMenu2I18n>;
17
17
  export type MainMenu2Item = {
18
18
  /** Visible label text */
19
- label: string;
19
+ label: string | NonNullable<ReactElement>;
20
20
  /** Un-abbreviated label set as `title=""` and `aria-label=""` */
21
21
  labelLong?: string;
22
22
  /** Language of the link label */
@@ -57,6 +57,7 @@ export type MainMenu2ButtonItem = MainMenu2Item & {
57
57
  };
58
58
  export type MainMenu2CustomItem = (props: {
59
59
  closeMenu: () => void;
60
+ openMenu: () => void;
60
61
  }) => ReactElement;
61
62
  export type MainMenu2SubMenuItem = MainMenu2Item & {
62
63
  descr?: string;
@@ -98,8 +99,10 @@ export type MainMenu2Props = {
98
99
  hot?: MainMenu2ButtonItemList;
99
100
  extra?: MainMenu2ButtonItemList;
100
101
  relatedTitle?: string;
101
- related?: MainMenu2ItemList;
102
+ related?: MainMenu2ButtonItemList;
102
103
  };
104
+ /** Visual type */
105
+ variant?: 'default' | 'light';
103
106
  /**
104
107
  * NOTE: Clicking a MainMenu2 item will automatically close HannaUIState's
105
108
  * "Hamburger menu" (a.k.a. "Mobile menu")
package/MainMenu2.js CHANGED
@@ -62,13 +62,13 @@ const iconMap = {
62
62
  * Whether we're rendering the menu on the server or in the browser, etc.
63
63
  */
64
64
  const getRenderers = (props) => {
65
- const { onItemClick, closeMenu, isBrowser } = props;
65
+ const { onItemClick, closeMenu, openMenu, isBrowser } = props;
66
66
  const renderItem = (classPrefix, item, opts = {}) => {
67
67
  const { key, Tag = 'li', button } = opts;
68
68
  if (typeof item === 'function') {
69
69
  const Item = item;
70
70
  return (react_1.default.createElement("li", { key: key, className: `${classPrefix}item` },
71
- react_1.default.createElement(Item, { closeMenu: closeMenu })));
71
+ react_1.default.createElement(Item, { closeMenu: closeMenu, openMenu: openMenu })));
72
72
  }
73
73
  const linkClassName = `${classPrefix}link`;
74
74
  const { label, labelLong, href, target, lang, controlsId, onClick, descr, icon } = item;
@@ -77,23 +77,32 @@ const getRenderers = (props) => {
77
77
  react_1.default.createElement("small", { className: `${linkClassName}__descr` }, descr)));
78
78
  const ButtonTag = button ? ButtonSecondary_js_1.default : 'button';
79
79
  const LinkTag = button ? ButtonSecondary_js_1.default : _Link_js_1.Link;
80
+ const commonProps = {
81
+ className: linkClassName,
82
+ 'data-icon': icon ? iconMap[icon] : undefined,
83
+ 'arial-label': labelLong,
84
+ title: labelLong,
85
+ lang,
86
+ };
80
87
  const buttonCompProps = button
81
88
  ? {
82
89
  size: 'small',
83
- 'data-icon': icon && iconMap[icon],
84
90
  }
85
91
  : undefined;
86
- return (react_1.default.createElement(Tag, { key: key, className: (0, classUtils_1.modifiedClass)(`${classPrefix}item`, item.modifier), "aria-current": item.current || undefined }, isBrowser && (onClick || !href) ? (react_1.default.createElement(ButtonTag, Object.assign({ className: linkClassName, type: "button", onClick: () => {
92
+ if (label === 'Græna planið') {
93
+ console.log('FOOBAR', icon, icon && iconMap[icon]);
94
+ }
95
+ return (react_1.default.createElement(Tag, { key: key, className: (0, classUtils_1.modifiedClass)(`${classPrefix}item`, item.modifier), "aria-current": item.current || undefined }, isBrowser && (onClick || href == null) ? (react_1.default.createElement(ButtonTag, Object.assign({}, commonProps, { type: "button", "aria-controls": controlsId, onClick: () => {
87
96
  const keepOpen1 = onClick && onClick(item) === false;
88
97
  const keepOpen2 = onItemClick && onItemClick(item) === false;
89
98
  !(keepOpen1 || keepOpen2) && closeMenu();
90
- }, "aria-controls": controlsId, "aria-label": labelLong, title: labelLong, lang: lang }, buttonCompProps),
99
+ } }, buttonCompProps),
91
100
  label,
92
101
  " ",
93
- itemDescr)) : href ? (react_1.default.createElement(LinkTag, Object.assign({ className: linkClassName, href: href, target: target, "aria-label": labelLong, title: labelLong, onClick: () => {
102
+ itemDescr)) : href != null ? (react_1.default.createElement(LinkTag, Object.assign({}, commonProps, { href: href, hrefLang: item.hrefLang, target: target, onClick: () => {
94
103
  const keepOpen = onItemClick && onItemClick(item) === false;
95
104
  !keepOpen && closeMenu();
96
- }, lang: lang, hrefLang: item.hrefLang }, buttonCompProps),
105
+ } }, buttonCompProps),
97
106
  label,
98
107
  " ",
99
108
  itemDescr)) : null));
@@ -108,7 +117,7 @@ const getRenderers = (props) => {
108
117
  };
109
118
  // eslint-disable-next-line complexity
110
119
  const MainMenu2 = (props) => {
111
- const { homeLink = '/', items, onItemClick, illustration, imageUrl, wrapperProps = {}, } = props;
120
+ const { homeLink = '/', items, onItemClick, illustration, imageUrl, variant, wrapperProps = {}, } = props;
112
121
  const domid = (0, utils_js_1.useDomid)(wrapperProps.id);
113
122
  const isBrowser = (0, utils_js_1.useIsBrowserSide)(props.ssr);
114
123
  const [isMenuOpen, setIsMenuOpen] = (0, react_1.useState)(false);
@@ -181,6 +190,7 @@ const MainMenu2 = (props) => {
181
190
  const { renderItem, renderList } = getRenderers({
182
191
  onItemClick,
183
192
  closeMenu,
193
+ openMenu,
184
194
  isBrowser,
185
195
  });
186
196
  const homeLinkItem = Object.assign(Object.assign({}, (typeof homeLink === 'string'
@@ -188,7 +198,10 @@ const MainMenu2 = (props) => {
188
198
  : homeLink)), { modifier: 'home' });
189
199
  const menuImageUrl = imageUrl || (illustration && (0, assets_1.getIllustrationUrl)(illustration));
190
200
  const menuId = `${domid}-menu`;
191
- return (react_1.default.createElement("nav", Object.assign({}, props.wrapperProps, { className: (0, classUtils_1.modifiedClass)('MainMenu2', isBrowser && (isMenuOpen ? 'open' : 'closed'), wrapperProps.className), style: menuImageUrl
201
+ return (react_1.default.createElement("nav", Object.assign({}, props.wrapperProps, { className: (0, classUtils_1.modifiedClass)('MainMenu2', [
202
+ isBrowser && (isMenuOpen ? 'open' : 'closed'),
203
+ variant && variant !== 'default' ? `variant--${variant}` : undefined,
204
+ ], wrapperProps.className), style: menuImageUrl
192
205
  ? Object.assign(Object.assign({}, wrapperProps.style), { '--menu-image': `url(${menuImageUrl})` })
193
206
  : wrapperProps.style, ref: wrapperRef, "aria-label": txt.title, "data-sprinkled": isBrowser, id: menuId }),
194
207
  isMenuOpen && react_1.default.createElement(FocusTrap_js_1.FocusTrap, { atTop: true }),
package/esm/MainMenu.js CHANGED
@@ -104,8 +104,11 @@ export const _MainMenu = (props) => {
104
104
  const htmlElmDataset = htmlElm.dataset;
105
105
  // const menuElm = menuElmRef.current as HTMLElement;
106
106
  _setActivePanel((activePanel) => {
107
+ if (!newActive && !activePanel) {
108
+ return undefined;
109
+ }
107
110
  if (!newActive) {
108
- activePanel && setLaggyActivePanel(activePanel, 1000);
111
+ setLaggyActivePanel(activePanel, 1000);
109
112
  htmlElm.scrollTop = parseInt(htmlElmDataset.scrollTop || '') || 0;
110
113
  delete htmlElmDataset.scrollTop;
111
114
  delete htmlElmDataset.megaPanelActive;
@@ -16,7 +16,7 @@ export type MainMenu2I18n = {
16
16
  export declare const defaultMainMenu2Texts: DefaultTexts<MainMenu2I18n>;
17
17
  export type MainMenu2Item = {
18
18
  /** Visible label text */
19
- label: string;
19
+ label: string | NonNullable<ReactElement>;
20
20
  /** Un-abbreviated label set as `title=""` and `aria-label=""` */
21
21
  labelLong?: string;
22
22
  /** Language of the link label */
@@ -57,6 +57,7 @@ export type MainMenu2ButtonItem = MainMenu2Item & {
57
57
  };
58
58
  export type MainMenu2CustomItem = (props: {
59
59
  closeMenu: () => void;
60
+ openMenu: () => void;
60
61
  }) => ReactElement;
61
62
  export type MainMenu2SubMenuItem = MainMenu2Item & {
62
63
  descr?: string;
@@ -98,8 +99,10 @@ export type MainMenu2Props = {
98
99
  hot?: MainMenu2ButtonItemList;
99
100
  extra?: MainMenu2ButtonItemList;
100
101
  relatedTitle?: string;
101
- related?: MainMenu2ItemList;
102
+ related?: MainMenu2ButtonItemList;
102
103
  };
104
+ /** Visual type */
105
+ variant?: 'default' | 'light';
103
106
  /**
104
107
  * NOTE: Clicking a MainMenu2 item will automatically close HannaUIState's
105
108
  * "Hamburger menu" (a.k.a. "Mobile menu")
package/esm/MainMenu2.js CHANGED
@@ -58,13 +58,13 @@ const iconMap = {
58
58
  * Whether we're rendering the menu on the server or in the browser, etc.
59
59
  */
60
60
  const getRenderers = (props) => {
61
- const { onItemClick, closeMenu, isBrowser } = props;
61
+ const { onItemClick, closeMenu, openMenu, isBrowser } = props;
62
62
  const renderItem = (classPrefix, item, opts = {}) => {
63
63
  const { key, Tag = 'li', button } = opts;
64
64
  if (typeof item === 'function') {
65
65
  const Item = item;
66
66
  return (React.createElement("li", { key: key, className: `${classPrefix}item` },
67
- React.createElement(Item, { closeMenu: closeMenu })));
67
+ React.createElement(Item, { closeMenu: closeMenu, openMenu: openMenu })));
68
68
  }
69
69
  const linkClassName = `${classPrefix}link`;
70
70
  const { label, labelLong, href, target, lang, controlsId, onClick, descr, icon } = item;
@@ -73,23 +73,32 @@ const getRenderers = (props) => {
73
73
  React.createElement("small", { className: `${linkClassName}__descr` }, descr)));
74
74
  const ButtonTag = button ? ButtonSecondary : 'button';
75
75
  const LinkTag = button ? ButtonSecondary : Link;
76
+ const commonProps = {
77
+ className: linkClassName,
78
+ 'data-icon': icon ? iconMap[icon] : undefined,
79
+ 'arial-label': labelLong,
80
+ title: labelLong,
81
+ lang,
82
+ };
76
83
  const buttonCompProps = button
77
84
  ? {
78
85
  size: 'small',
79
- 'data-icon': icon && iconMap[icon],
80
86
  }
81
87
  : undefined;
82
- return (React.createElement(Tag, { key: key, className: modifiedClass(`${classPrefix}item`, item.modifier), "aria-current": item.current || undefined }, isBrowser && (onClick || !href) ? (React.createElement(ButtonTag, Object.assign({ className: linkClassName, type: "button", onClick: () => {
88
+ if (label === 'Græna planið') {
89
+ console.log('FOOBAR', icon, icon && iconMap[icon]);
90
+ }
91
+ return (React.createElement(Tag, { key: key, className: modifiedClass(`${classPrefix}item`, item.modifier), "aria-current": item.current || undefined }, isBrowser && (onClick || href == null) ? (React.createElement(ButtonTag, Object.assign({}, commonProps, { type: "button", "aria-controls": controlsId, onClick: () => {
83
92
  const keepOpen1 = onClick && onClick(item) === false;
84
93
  const keepOpen2 = onItemClick && onItemClick(item) === false;
85
94
  !(keepOpen1 || keepOpen2) && closeMenu();
86
- }, "aria-controls": controlsId, "aria-label": labelLong, title: labelLong, lang: lang }, buttonCompProps),
95
+ } }, buttonCompProps),
87
96
  label,
88
97
  " ",
89
- itemDescr)) : href ? (React.createElement(LinkTag, Object.assign({ className: linkClassName, href: href, target: target, "aria-label": labelLong, title: labelLong, onClick: () => {
98
+ itemDescr)) : href != null ? (React.createElement(LinkTag, Object.assign({}, commonProps, { href: href, hrefLang: item.hrefLang, target: target, onClick: () => {
90
99
  const keepOpen = onItemClick && onItemClick(item) === false;
91
100
  !keepOpen && closeMenu();
92
- }, lang: lang, hrefLang: item.hrefLang }, buttonCompProps),
101
+ } }, buttonCompProps),
93
102
  label,
94
103
  " ",
95
104
  itemDescr)) : null));
@@ -104,7 +113,7 @@ const getRenderers = (props) => {
104
113
  };
105
114
  // eslint-disable-next-line complexity
106
115
  export const MainMenu2 = (props) => {
107
- const { homeLink = '/', items, onItemClick, illustration, imageUrl, wrapperProps = {}, } = props;
116
+ const { homeLink = '/', items, onItemClick, illustration, imageUrl, variant, wrapperProps = {}, } = props;
108
117
  const domid = useDomid(wrapperProps.id);
109
118
  const isBrowser = useIsBrowserSide(props.ssr);
110
119
  const [isMenuOpen, setIsMenuOpen] = useState(false);
@@ -177,6 +186,7 @@ export const MainMenu2 = (props) => {
177
186
  const { renderItem, renderList } = getRenderers({
178
187
  onItemClick,
179
188
  closeMenu,
189
+ openMenu,
180
190
  isBrowser,
181
191
  });
182
192
  const homeLinkItem = Object.assign(Object.assign({}, (typeof homeLink === 'string'
@@ -184,7 +194,10 @@ export const MainMenu2 = (props) => {
184
194
  : homeLink)), { modifier: 'home' });
185
195
  const menuImageUrl = imageUrl || (illustration && getIllustrationUrl(illustration));
186
196
  const menuId = `${domid}-menu`;
187
- return (React.createElement("nav", Object.assign({}, props.wrapperProps, { className: modifiedClass('MainMenu2', isBrowser && (isMenuOpen ? 'open' : 'closed'), wrapperProps.className), style: menuImageUrl
197
+ return (React.createElement("nav", Object.assign({}, props.wrapperProps, { className: modifiedClass('MainMenu2', [
198
+ isBrowser && (isMenuOpen ? 'open' : 'closed'),
199
+ variant && variant !== 'default' ? `variant--${variant}` : undefined,
200
+ ], wrapperProps.className), style: menuImageUrl
188
201
  ? Object.assign(Object.assign({}, wrapperProps.style), { '--menu-image': `url(${menuImageUrl})` })
189
202
  : wrapperProps.style, ref: wrapperRef, "aria-label": txt.title, "data-sprinkled": isBrowser, id: menuId }),
190
203
  isMenuOpen && React.createElement(FocusTrap, { atTop: true }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/hanna-react",
3
- "version": "0.10.133",
3
+ "version": "0.10.135",
4
4
  "author": "Reykjavík (http://www.reykjavik.is)",
5
5
  "contributors": [
6
6
  "Hugsmiðjan ehf (http://www.hugsmidjan.is)",
@@ -18,7 +18,7 @@
18
18
  "@hugsmidjan/qj": "^4.22.1",
19
19
  "@hugsmidjan/react": "^0.4.32",
20
20
  "@reykjavik/hanna-css": "^0.4.14",
21
- "@reykjavik/hanna-utils": "^0.2.15",
21
+ "@reykjavik/hanna-utils": "^0.2.16",
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",