@linzjs/lui 17.11.3 → 17.12.2

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
@@ -1,3 +1,24 @@
1
+ ## [17.12.2](https://github.com/linz/lui/compare/v17.12.1...v17.12.2) (2022-08-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** moving react-aria related dependencies out of dev so consuming apps dont need to install them when building ([#742](https://github.com/linz/lui/issues/742)) ([79d78f6](https://github.com/linz/lui/commit/79d78f6121e32cddd3fc39818eb741b36dd6e6d1))
7
+
8
+ ## [17.12.1](https://github.com/linz/lui/compare/v17.12.0...v17.12.1) (2022-08-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Fixes dealing app path in app switcher menu ([#741](https://github.com/linz/lui/issues/741)) ([bad6d5e](https://github.com/linz/lui/commit/bad6d5ebdd237576ec03f84c5094ae4321086d6f))
14
+
15
+ # [17.12.0](https://github.com/linz/lui/compare/v17.11.3...v17.12.0) (2022-08-28)
16
+
17
+
18
+ ### Features
19
+
20
+ * **LuiListBox:** Adding support for groups ([#739](https://github.com/linz/lui/issues/739)) ([797c421](https://github.com/linz/lui/commit/797c42117e615aee47b2ac33aad50ef6a1957d5d))
21
+
1
22
  ## [17.11.3](https://github.com/linz/lui/compare/v17.11.2...v17.11.3) (2022-08-24)
2
23
 
3
24
 
@@ -2,12 +2,27 @@ import './LuiListBox.scss';
2
2
  import { HTMLAttributes, Key, ReactNode } from 'react';
3
3
  import { SelectionBehavior, SelectionMode } from '@react-types/shared';
4
4
  import { AriaListBoxOptions } from '@react-aria/listbox';
5
- export declare type ItemWithKey<T> = T & {
5
+ export declare type KeyGetter<T> = (item: T) => Key;
6
+ export declare type GroupGetter<T> = (item: T) => string | null;
7
+ export interface ILuiListItemNode<T> {
6
8
  key: Key;
7
- };
9
+ textValue: string;
10
+ childNodes?: ILuiListItemNode<T>[];
11
+ value?: T;
12
+ }
8
13
  export interface ILuiListBoxItem extends Object {
9
14
  key: Key;
10
15
  label: ReactNode;
16
+ group?: string;
17
+ }
18
+ export interface IItemRendererProps<T> {
19
+ item: T;
20
+ isSelected: boolean;
21
+ isDisabled: boolean;
22
+ isFocusVisible: boolean;
23
+ }
24
+ export interface IGroupHeadingRendererProps {
25
+ text: string;
11
26
  }
12
27
  export interface ILuiListBoxProps<T = ILuiListBoxItem> extends Omit<HTMLAttributes<HTMLUListElement>, 'onChange'> {
13
28
  ariaLabel?: string;
@@ -16,18 +31,14 @@ export interface ILuiListBoxProps<T = ILuiListBoxItem> extends Omit<HTMLAttribut
16
31
  value?: Key | Key[];
17
32
  disabled?: boolean;
18
33
  onChange?: (keys: Key[], items: T[]) => void;
19
- ariaProps?: Omit<AriaListBoxOptions<ItemWithKey<T>>, 'children' | 'selectedKeys' | 'onSelectionChange' | 'selectionMode'>;
34
+ ariaProps?: Omit<AriaListBoxOptions<ILuiListItemNode<T>>, 'children' | 'selectedKeys' | 'onSelectionChange' | 'selectionMode'>;
20
35
  selectionMode?: SelectionMode;
21
36
  selectionBehavior?: SelectionBehavior;
22
37
  itemRenderer?: (props: IItemRendererProps<T>) => ReactNode;
23
- getKey?: (item: T) => Key;
38
+ groupHeadingRenderer?: (props: IGroupHeadingRendererProps) => ReactNode;
39
+ getKey?: KeyGetter<T>;
40
+ getGroup?: GroupGetter<T>;
24
41
  loadingIndicator?: () => ReactNode;
25
42
  emptyIndicator?: () => ReactNode;
26
43
  }
27
- export interface IItemRendererProps<T> {
28
- item: T;
29
- isSelected: boolean;
30
- isDisabled: boolean;
31
- isFocusVisible: boolean;
32
- }
33
- export declare function LuiListBox<T extends object = ILuiListBoxItem>({ ariaLabel, ariaLabelledBy, itemRenderer, loadingIndicator, emptyIndicator, selectionMode, selectionBehavior, disabled, items, value, onChange, getKey, ariaProps, className, ...ulProps }: ILuiListBoxProps<T>): JSX.Element;
44
+ export declare function LuiListBox<T extends object = ILuiListBoxItem>({ ariaLabel, ariaLabelledBy, itemRenderer, groupHeadingRenderer, loadingIndicator, emptyIndicator, selectionMode, selectionBehavior, disabled, items, value, onChange, getKey, getGroup, ariaProps, className, ...ulProps }: ILuiListBoxProps<T>): JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { ListState } from '@react-stately/list';
2
+ import { ReactNode } from 'react';
3
+ import { IGroupHeadingRendererProps, IItemRendererProps, ILuiListItemNode } from './LuiListBox';
4
+ export interface ILuiListBoxSectionProps<T> {
5
+ group: ILuiListItemNode<T>;
6
+ state: ListState<ILuiListItemNode<T>>;
7
+ headingRenderer: (props: IGroupHeadingRendererProps) => ReactNode;
8
+ itemRenderer: (item: IItemRendererProps<T>) => ReactNode;
9
+ }
10
+ export declare function LuiListBoxGroup<T>({ group, state, headingRenderer, itemRenderer, }: ILuiListBoxSectionProps<T>): JSX.Element;
@@ -1,10 +1,9 @@
1
- import { Node } from '@react-types/shared';
2
1
  import { ReactNode } from 'react';
3
- import { IItemRendererProps } from './LuiListBox';
2
+ import { IItemRendererProps, ILuiListItemNode } from './LuiListBox';
4
3
  import { ListState } from '@react-stately/list';
5
4
  export interface ILuiListBoxItemProps<T> {
6
- node: Node<T>;
7
- state: ListState<T>;
8
- renderer?: (item: IItemRendererProps<T>) => ReactNode;
5
+ node: ILuiListItemNode<T>;
6
+ state: ListState<ILuiListItemNode<T>>;
7
+ renderer: (item: IItemRendererProps<T>) => ReactNode;
9
8
  }
10
9
  export default function LuiListBoxItem<T>({ node, state, renderer, }: ILuiListBoxItemProps<T>): JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { ListProps } from '@react-stately/list';
2
+ import { ILuiListBoxProps, ILuiListItemNode } from './LuiListBox';
3
+ export declare function useLuiListBox<T extends object>({ selectionMode, selectionBehavior, items, value, onChange, ariaProps, getGroup, getKey, }: ILuiListBoxProps<T>): ListProps<ILuiListItemNode<T>>;
package/dist/index.js CHANGED
@@ -28978,7 +28978,7 @@ const LOLAppLauncherMenu = (props) => {
28978
28978
  ]));
28979
28979
  }
28980
28980
  if (!isInternal() && enableTitlesLink) {
28981
- links.push(createLink(pathname, TITLES_LABEL, '/dealings', TitlesIconActive, TitlesIcon, [
28981
+ links.push(createLink(pathname, TITLES_LABEL, '/dealing', TitlesIconActive, TitlesIcon, [
28982
28982
  'prv_cancel_with_deal',
28983
28983
  'prv_create_deal_tin',
28984
28984
  'prv_edit_modify_deal_tin',
@@ -40396,7 +40396,7 @@ const LuiAccordicardStatic = (props) => {
40396
40396
  React__default["default"].createElement(LuiIcon, { className: clsx('LuiAccordicardStatic-chevron', isOpen ? 'LuiAccordicardStatic-chevron--isOpen' : null), name: 'ic_expand_more', alt: "expand", title: "Expand and collapse panel", size: "md" }))));
40397
40397
  };
40398
40398
 
40399
- var css_248z$2 = "/**\n @deprecated\n */\n/**\n @deprecated\n */\n/**\n @deprecated\n */\n.LuiListBox {\n padding: 0;\n list-style: none;\n}\n.LuiListBox .LuiListBoxItem {\n font-family: \"Open Sans\", system-ui, sans-serif;\n font-style: normal;\n font-weight: normal;\n user-select: none;\n color: #2a292c;\n line-height: 24px;\n outline: none;\n padding: 0.5rem 0.75rem;\n border: 2px solid transparent;\n}\n.LuiListBox .LuiListBoxItem:focus-visible {\n border-color: #007198;\n}\n.LuiListBox .LuiListBoxItem.LuiListBoxItem-selected {\n background: #e2f3f7;\n}\n.LuiListBox .LuiListBoxItem:hover, .LuiListBox .LuiListBoxItem.LuiListBoxItem-selected:hover {\n background: #d6eef4;\n}\n.LuiListBox .LuiListBoxItem.LuiListBoxItem-disabled {\n background: #eaeaea;\n}\n.LuiListBox .LuiListBox-emptyIndicator, .LuiListBox .LuiListBox-loadingIndicator {\n padding: 0.5rem 0.75rem;\n}";
40399
+ var css_248z$2 = "/**\n @deprecated\n */\n/**\n @deprecated\n */\n/**\n @deprecated\n */\n.LuiListBox {\n padding: 0;\n list-style: none;\n}\n.LuiListBox .LuiListBoxItem {\n font-family: \"Open Sans\", system-ui, sans-serif;\n font-style: normal;\n font-weight: normal;\n user-select: none;\n color: #2a292c;\n line-height: 24px;\n outline: none;\n padding: 0.5rem 0.75rem;\n border: 2px solid transparent;\n}\n.LuiListBox .LuiListBoxItem:focus-visible {\n border-color: #007198;\n}\n.LuiListBox .LuiListBoxItem.LuiListBoxItem-selected {\n background: #e2f3f7;\n}\n.LuiListBox .LuiListBoxItem:hover, .LuiListBox .LuiListBoxItem.LuiListBoxItem-selected:hover {\n background: #d6eef4;\n}\n.LuiListBox .LuiListBoxItem.LuiListBoxItem-disabled {\n background: #eaeaea;\n}\n.LuiListBox .LuiListBox-emptyIndicator, .LuiListBox .LuiListBox-loadingIndicator {\n padding: 0.5rem 0.75rem;\n}\n.LuiListBox .LuiListBoxGroup .LuiListBoxGroup-heading {\n font-family: \"Open Sans\", system-ui, sans-serif;\n font-style: normal;\n font-weight: normal;\n font-size: 14px;\n user-select: none;\n color: #6b6966;\n line-height: 16px;\n padding: 0.5rem 0.5rem;\n}";
40400
40400
  styleInject(css_248z$2);
40401
40401
 
40402
40402
  function $c1d7fb2ec91bae71$var$Item(props) {
@@ -40444,6 +40444,42 @@ let $c1d7fb2ec91bae71$export$6d08773d2e66f8f2 = $c1d7fb2ec91bae71$var$Item;
40444
40444
 
40445
40445
 
40446
40446
 
40447
+ function $9fc4852771d079eb$var$Section(props) {
40448
+ return null;
40449
+ }
40450
+ $9fc4852771d079eb$var$Section.getCollectionNode = function* getCollectionNode(props) {
40451
+ let { children: children , title: title , items: items1 } = props;
40452
+ yield {
40453
+ type: 'section',
40454
+ hasChildNodes: true,
40455
+ rendered: title,
40456
+ 'aria-label': props['aria-label'],
40457
+ *childNodes () {
40458
+ if (typeof children === 'function') {
40459
+ if (!items1) throw new Error('props.children was a function but props.items is missing');
40460
+ for (let item of items1)yield {
40461
+ type: 'item',
40462
+ value: item,
40463
+ renderer: children
40464
+ };
40465
+ } else {
40466
+ let items = [];
40467
+ React__default["default"].Children.forEach(children, (child)=>{
40468
+ items.push({
40469
+ type: 'item',
40470
+ element: child
40471
+ });
40472
+ });
40473
+ yield* items;
40474
+ }
40475
+ }
40476
+ };
40477
+ };
40478
+ // We don't want getCollectionNode to show up in the type definition
40479
+ let $9fc4852771d079eb$export$6e2c8f0811a474ce = $9fc4852771d079eb$var$Section;
40480
+
40481
+
40482
+
40447
40483
  class $eb2240fc39a57fa5$export$bf788dd355e3a401 {
40448
40484
  build(props, context) {
40449
40485
  this.context = context;
@@ -40649,38 +40685,68 @@ function $453cc9f0df89c0a5$export$77d5aafae4e095b2(collection) {
40649
40685
  return count;
40650
40686
  }
40651
40687
 
40652
- function mapToAriaListBoxProps({ selectionMode, selectionBehavior, items = [], value, onChange, ariaProps, getKey = (item) => {
40653
- if (!item.hasOwnProperty('key')) {
40654
- throw Error('Could not find `key` property on item, please provide a custom `getKey` function');
40655
- }
40656
- return item.key;
40657
- }, }) {
40688
+ function useLuiListBox({ selectionMode, selectionBehavior, items = [], value, onChange, ariaProps, getGroup = defaultGroupGetter, getKey = defaultKeyGetter, }) {
40689
+ const children = React.useCallback((item) => item.childNodes ? (React__default["default"].createElement($9fc4852771d079eb$export$6e2c8f0811a474ce, { key: item.key, items: item.childNodes, title: item.textValue }, (item) => React__default["default"].createElement($c1d7fb2ec91bae71$export$6d08773d2e66f8f2, null, String(item.key)))) : (React__default["default"].createElement($c1d7fb2ec91bae71$export$6d08773d2e66f8f2, null, String(item.key))), []);
40690
+ const onSelectionChange = React.useCallback((keys) => {
40691
+ if (!onChange) {
40692
+ return;
40693
+ }
40694
+ onChange(keys === 'all' ? items.map((item) => getKey(item)) : Array.from(keys), keys === 'all' ? items : items.filter((item) => keys.has(getKey(item))));
40695
+ }, [items, onChange, getKey]);
40696
+ const nodes = React.useMemo(() => mapItemsToNodes(items, getKey, getGroup), [
40697
+ items,
40698
+ getKey,
40699
+ getGroup,
40700
+ ]);
40658
40701
  return {
40659
40702
  ...ariaProps,
40660
- items: items?.map((item) => {
40661
- if (item.hasOwnProperty('key')) {
40662
- return item;
40663
- }
40664
- return { ...item, key: getKey(item) };
40665
- }),
40703
+ items: nodes,
40666
40704
  selectionMode,
40667
40705
  selectionBehavior,
40668
40706
  selectedKeys: (Array.isArray(value) ? value : [value]).filter(Boolean),
40669
- children: (item) => React__default["default"].createElement($c1d7fb2ec91bae71$export$6d08773d2e66f8f2, null, String(item.key)),
40670
- ...(onChange
40671
- ? {
40672
- onSelectionChange: (keys) => {
40673
- const selectedItems = keys === 'all'
40674
- ? items
40675
- : items.filter((item) => keys.has(getKey(item)));
40676
- const selectedKeys = keys === 'all'
40677
- ? items.map((item) => getKey(item))
40678
- : Array.from(keys);
40679
- onChange(selectedKeys, selectedItems);
40680
- },
40681
- }
40682
- : {}),
40707
+ children,
40708
+ onSelectionChange,
40683
40709
  };
40710
+ }
40711
+ function mapItemsToNodes(items, getKey, getGroup) {
40712
+ const rootNodes = new Map();
40713
+ for (const item of items) {
40714
+ const groupName = getGroup(item);
40715
+ const key = getKey(item);
40716
+ // Is an item without a group
40717
+ if (!groupName) {
40718
+ rootNodes.set(key, {
40719
+ key,
40720
+ textValue: String(key),
40721
+ value: item,
40722
+ });
40723
+ }
40724
+ // is an item with a group that has not been encountered yet.
40725
+ if (groupName && !rootNodes.get(groupName)) {
40726
+ rootNodes.set(groupName, {
40727
+ key: groupName,
40728
+ textValue: groupName,
40729
+ childNodes: [],
40730
+ });
40731
+ }
40732
+ if (groupName) {
40733
+ rootNodes.get(groupName).childNodes.push({
40734
+ key,
40735
+ textValue: String(key),
40736
+ value: item,
40737
+ });
40738
+ }
40739
+ }
40740
+ return Array.from(rootNodes.values());
40741
+ }
40742
+ function defaultKeyGetter(item) {
40743
+ if (!item.hasOwnProperty('key')) {
40744
+ throw Error('Could not find `key` property on item, please provide a custom `getKey` function');
40745
+ }
40746
+ return item.key;
40747
+ }
40748
+ function defaultGroupGetter(item) {
40749
+ return item.group || null;
40684
40750
  }
40685
40751
 
40686
40752
  function $458b0a5536c1a7cf$export$40bfa8c7b0832715(value1, defaultValue, onChange) {
@@ -43271,20 +43337,41 @@ function $293f70390ea03370$export$497855f14858aa34(props, state, ref) {
43271
43337
  };
43272
43338
  }
43273
43339
 
43340
+
43341
+
43342
+ function $af383d3bef1cfdc9$export$c3f9f39876e4bc7(props) {
43343
+ let { heading: heading , 'aria-label': ariaLabel } = props;
43344
+ let headingId = $bdb11010cef70236$export$f680877a34711e37();
43345
+ return {
43346
+ itemProps: {
43347
+ role: 'presentation'
43348
+ },
43349
+ headingProps: heading ? {
43350
+ // Techincally, listbox cannot contain headings according to ARIA.
43351
+ // We hide the heading from assistive technology, and only use it
43352
+ // as a label for the nested group.
43353
+ id: headingId,
43354
+ 'aria-hidden': true
43355
+ } : {
43356
+ },
43357
+ groupProps: {
43358
+ role: 'group',
43359
+ 'aria-label': ariaLabel,
43360
+ 'aria-labelledby': heading ? headingId : undefined
43361
+ }
43362
+ };
43363
+ }
43364
+
43274
43365
  function LuiListBoxItem({ node, state, renderer, }) {
43275
43366
  const ref = React.useRef(null);
43276
43367
  const { optionProps, isSelected, isDisabled } = $293f70390ea03370$export$497855f14858aa34({ key: node.key }, state, ref);
43277
43368
  const { isFocusVisible, focusProps } = $f7dceffc5ad7768b$export$4e328f61c538687f();
43278
- return (React__default["default"].createElement("li", { ref: ref, ...$3ef42575df84b30b$export$9d1611c77c2fe928(optionProps, focusProps), className: clsx('LuiListBoxItem', isSelected && 'LuiListBoxItem-selected', isDisabled && 'LuiListBoxItem-disabled') }, renderer
43279
- ? renderer({ item: node.value, isDisabled, isSelected, isFocusVisible })
43280
- : node.rendered));
43281
- }
43282
-
43283
- function DefaultItemRenderer({ item, }) {
43284
- if (!item.hasOwnProperty('label')) {
43285
- throw Error('Could not find `label` property on item, please provide a custom `itemRenderer`');
43286
- }
43287
- return React__default["default"].createElement(React__default["default"].Fragment, null, item.label);
43369
+ return (React__default["default"].createElement("li", { ref: ref, ...$3ef42575df84b30b$export$9d1611c77c2fe928(optionProps, focusProps), className: clsx('LuiListBoxItem', isSelected && 'LuiListBoxItem-selected', isDisabled && 'LuiListBoxItem-disabled') }, renderer({
43370
+ item: node.value,
43371
+ isDisabled,
43372
+ isSelected,
43373
+ isFocusVisible,
43374
+ })));
43288
43375
  }
43289
43376
 
43290
43377
  class $e40ea825a81a3709$export$52baac22726c72bf extends Set {
@@ -43756,27 +43843,28 @@ function $e72dd72e1c76a225$export$2f645645f7bca764(props) {
43756
43843
  };
43757
43844
  }
43758
43845
 
43759
- function LuiListBox({ ariaLabel, ariaLabelledBy, itemRenderer = DefaultItemRenderer, loadingIndicator = DefaultLoadingIndicator, emptyIndicator = DefaultEmptyIndicator, selectionMode = 'single', selectionBehavior = 'toggle', disabled = false, items, value, onChange = () => {
43760
- /* noop */
43761
- }, getKey, ariaProps, className, ...ulProps }) {
43762
- const listProps = React.useMemo(() => mapToAriaListBoxProps({
43846
+ function LuiListBoxGroup({ group, state, headingRenderer, itemRenderer, }) {
43847
+ let { itemProps, headingProps, groupProps } = $af383d3bef1cfdc9$export$c3f9f39876e4bc7({
43848
+ heading: group.textValue,
43849
+ 'aria-label': group.textValue,
43850
+ });
43851
+ return (React__default["default"].createElement("li", { className: "LuiListBoxGroup", ...itemProps },
43852
+ React__default["default"].createElement("span", { className: "LuiListBoxGroup-heading", ...headingProps }, headingRenderer({ text: group.textValue })),
43853
+ React__default["default"].createElement("ul", { className: "LuiListBoxGroup-items", ...groupProps }, (group.childNodes || []).map((node) => (React__default["default"].createElement(LuiListBoxItem, { key: node.key, node: node, state: state, renderer: itemRenderer }))))));
43854
+ }
43855
+
43856
+ function LuiListBox({ ariaLabel, ariaLabelledBy, itemRenderer = DefaultItemRenderer, groupHeadingRenderer = DefaultGroupHeadingRenderer, loadingIndicator = DefaultLoadingIndicator, emptyIndicator = DefaultEmptyIndicator, selectionMode = 'single', selectionBehavior = 'toggle', disabled = false, items, value, onChange, getKey, getGroup, ariaProps, className, ...ulProps }) {
43857
+ const listProps = useLuiListBox({
43763
43858
  selectionMode,
43764
43859
  selectionBehavior,
43765
43860
  items,
43766
43861
  value,
43767
43862
  onChange,
43768
43863
  getKey,
43864
+ getGroup,
43769
43865
  ariaProps,
43770
43866
  disabled,
43771
- }), [
43772
- selectionMode,
43773
- selectionBehavior,
43774
- items,
43775
- value,
43776
- onChange,
43777
- getKey,
43778
- ariaProps,
43779
- ]);
43867
+ });
43780
43868
  const ariaListBoxProps = React.useMemo(() => ({
43781
43869
  'aria-label': ariaLabel,
43782
43870
  'aria-labelledby': ariaLabelledBy,
@@ -43788,7 +43876,16 @@ function LuiListBox({ ariaLabel, ariaLabelledBy, itemRenderer = DefaultItemRende
43788
43876
  return (React__default["default"].createElement("ul", { ...ulProps, ...listBoxProps, ref: ref, className: clsx('LuiListBox', className) },
43789
43877
  !items && loadingIndicator(),
43790
43878
  items?.length === 0 && emptyIndicator(),
43791
- [...state.collection].map((node) => (React__default["default"].createElement(LuiListBoxItem, { key: node.key, node: node, state: state, renderer: itemRenderer })))));
43879
+ [...state.collection].map((node) => node.type === 'section' ? (React__default["default"].createElement(LuiListBoxGroup, { key: node.key, group: node.value, state: state, headingRenderer: groupHeadingRenderer, itemRenderer: itemRenderer })) : (React__default["default"].createElement(LuiListBoxItem, { key: node.key, node: node.value, state: state, renderer: itemRenderer })))));
43880
+ }
43881
+ function DefaultItemRenderer({ item, }) {
43882
+ if (!item.hasOwnProperty('label')) {
43883
+ throw Error('Could not find `label` property on item, please provide a custom `itemRenderer`');
43884
+ }
43885
+ return React__default["default"].createElement(React__default["default"].Fragment, null, item.label);
43886
+ }
43887
+ function DefaultGroupHeadingRenderer({ text, }) {
43888
+ return text;
43792
43889
  }
43793
43890
  function DefaultLoadingIndicator() {
43794
43891
  return (React__default["default"].createElement(React__default["default"].Fragment, null,