@udixio/ui-react 2.10.2 → 2.10.4
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 +22 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +1990 -2014
- package/dist/lib/components/ContextMenu.d.ts +1 -1
- package/dist/lib/components/ContextMenu.d.ts.map +1 -1
- package/dist/lib/components/Menu.d.ts +1 -1
- package/dist/lib/components/Menu.d.ts.map +1 -1
- package/dist/lib/components/MenuItem.d.ts +1 -1
- package/dist/lib/components/MenuItem.d.ts.map +1 -1
- package/dist/lib/components/TextField.d.ts.map +1 -1
- package/dist/lib/interfaces/index.d.ts +2 -0
- package/dist/lib/interfaces/index.d.ts.map +1 -1
- package/dist/lib/interfaces/menu-item.interface.d.ts +19 -25
- package/dist/lib/interfaces/menu-item.interface.d.ts.map +1 -1
- package/dist/lib/interfaces/menu.interface.d.ts +0 -1
- package/dist/lib/interfaces/menu.interface.d.ts.map +1 -1
- package/dist/lib/interfaces/text-field.interface.d.ts +2 -5
- package/dist/lib/interfaces/text-field.interface.d.ts.map +1 -1
- package/dist/lib/styles/menu-group.style.d.ts +2 -2
- package/dist/lib/styles/menu-item.style.d.ts +58 -14
- package/dist/lib/styles/menu-item.style.d.ts.map +1 -1
- package/dist/lib/styles/menu.style.d.ts +0 -1
- package/dist/lib/styles/menu.style.d.ts.map +1 -1
- package/dist/lib/styles/text-field.style.d.ts +2 -10
- package/dist/lib/styles/text-field.style.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/components/ContextMenu.tsx +2 -4
- package/src/lib/components/Menu.tsx +1 -26
- package/src/lib/components/MenuItem.tsx +39 -21
- package/src/lib/components/TextField.tsx +55 -37
- package/src/lib/interfaces/index.ts +2 -0
- package/src/lib/interfaces/menu-item.interface.ts +20 -26
- package/src/lib/interfaces/menu.interface.ts +0 -1
- package/src/lib/interfaces/text-field.interface.ts +7 -8
- package/src/lib/styles/menu-item.style.ts +7 -15
|
@@ -2,9 +2,9 @@ import React, { useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
|
2
2
|
import { Icon } from '../icon';
|
|
3
3
|
import {
|
|
4
4
|
faCalendarDays,
|
|
5
|
-
faCircleExclamation,
|
|
6
5
|
faChevronDown,
|
|
7
6
|
faChevronUp,
|
|
7
|
+
faCircleExclamation,
|
|
8
8
|
} from '@fortawesome/free-solid-svg-icons';
|
|
9
9
|
import { motion } from 'motion/react';
|
|
10
10
|
import { DatePicker } from './DatePicker';
|
|
@@ -323,7 +323,7 @@ export const TextField = ({
|
|
|
323
323
|
});
|
|
324
324
|
|
|
325
325
|
const TextComponent = multiline ? TextareaAutosize : 'input';
|
|
326
|
-
// For select, we want the input to be readOnly but still focusable?
|
|
326
|
+
// For select, we want the input to be readOnly but still focusable?
|
|
327
327
|
// Actually, for better UX, standard select inputs are often readOnly text fields.
|
|
328
328
|
const textComponentProps = multiline
|
|
329
329
|
? {}
|
|
@@ -345,8 +345,8 @@ export const TextField = ({
|
|
|
345
345
|
<div ref={textFieldRef} className={styles.textField} style={style}>
|
|
346
346
|
<fieldset
|
|
347
347
|
onClick={() => {
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
if (isSelectInput) handleSelectToggle();
|
|
349
|
+
else focusInput();
|
|
350
350
|
}}
|
|
351
351
|
className={styles.content}
|
|
352
352
|
role="presentation"
|
|
@@ -424,11 +424,11 @@ export const TextField = ({
|
|
|
424
424
|
name={name}
|
|
425
425
|
placeholder={isFocused ? (placeholder ?? undefined) : ''}
|
|
426
426
|
onFocus={() => {
|
|
427
|
-
|
|
427
|
+
if (!isSelectInput) setIsFocused(true);
|
|
428
428
|
}}
|
|
429
429
|
onBlur={() => {
|
|
430
|
-
|
|
431
|
-
|
|
430
|
+
// For select, we manage focus manually with menu state usually
|
|
431
|
+
if (!isSelectInput) setIsFocused(false);
|
|
432
432
|
}}
|
|
433
433
|
disabled={disabled}
|
|
434
434
|
autoComplete={autoComplete}
|
|
@@ -531,38 +531,56 @@ export const TextField = ({
|
|
|
531
531
|
)}
|
|
532
532
|
|
|
533
533
|
{isSelectInput && showMenu && (
|
|
534
|
-
<AnchorPositioner
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
534
|
+
<AnchorPositioner
|
|
535
|
+
anchorRef={textFieldRef}
|
|
536
|
+
position="bottom"
|
|
537
|
+
style={{ width: textFieldRef.current?.offsetWidth }}
|
|
538
|
+
>
|
|
539
|
+
<div ref={menuRef}>
|
|
540
|
+
<Menu selected={value}>
|
|
541
|
+
{children
|
|
542
|
+
? React.Children.map(children, (child) => {
|
|
543
|
+
if (
|
|
544
|
+
React.isValidElement(child) &&
|
|
545
|
+
child.type === MenuItem
|
|
546
|
+
) {
|
|
547
|
+
return React.cloneElement(child, {
|
|
548
|
+
onClick: (e: React.MouseEvent) => {
|
|
549
|
+
if (child.props.onClick) {
|
|
550
|
+
child.props.onClick(e);
|
|
551
|
+
}
|
|
552
|
+
handleSelectOption(child.props.value ?? '');
|
|
553
|
+
},
|
|
554
|
+
} as any);
|
|
555
|
+
}
|
|
556
|
+
return child;
|
|
557
|
+
})
|
|
558
|
+
: options?.map((opt, i) => {
|
|
559
|
+
if (opt.type === 'divider') {
|
|
560
|
+
return <Divider key={i} className="my-1" />;
|
|
561
|
+
}
|
|
562
|
+
if (opt.type === 'headline') {
|
|
563
|
+
return <MenuHeadline key={i} label={opt.label} />;
|
|
564
|
+
}
|
|
565
|
+
return (
|
|
566
|
+
<MenuItem
|
|
567
|
+
key={opt.value ?? i}
|
|
568
|
+
onClick={(e) => {
|
|
569
|
+
if (opt.onClick) {
|
|
570
|
+
opt.onClick(e);
|
|
571
|
+
}
|
|
572
|
+
handleSelectOption(opt.value ?? '');
|
|
573
|
+
}}
|
|
574
|
+
{...opt}
|
|
575
|
+
>
|
|
576
|
+
{opt.label}
|
|
577
|
+
</MenuItem>
|
|
578
|
+
);
|
|
579
|
+
})}
|
|
580
|
+
</Menu>
|
|
581
|
+
</div>
|
|
563
582
|
</AnchorPositioner>
|
|
564
583
|
)}
|
|
565
584
|
</div>
|
|
566
585
|
);
|
|
567
586
|
};
|
|
568
|
-
|
|
@@ -10,6 +10,8 @@ export * from './fab.interface';
|
|
|
10
10
|
export * from './fab-menu.interface';
|
|
11
11
|
export * from './icon-button.interface';
|
|
12
12
|
export * from './menu.interface';
|
|
13
|
+
export * from './menu-group.interface';
|
|
14
|
+
export * from './menu-item.interface';
|
|
13
15
|
export * from './progress-indicator.interface';
|
|
14
16
|
export * from './side-sheet.interface';
|
|
15
17
|
export * from './slider.interface';
|
|
@@ -1,35 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ActionOrLink } from '../utils/component';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
value: string | number;
|
|
3
|
+
type Props = {
|
|
5
4
|
label?: string;
|
|
6
5
|
children?: React.ReactNode;
|
|
7
6
|
leadingIcon?: any;
|
|
8
7
|
trailingIcon?: any;
|
|
9
8
|
disabled?: boolean;
|
|
10
|
-
selected?: boolean; // Injected by parent
|
|
11
9
|
variant?: 'standard' | 'vibrant'; // Injected by parent
|
|
12
10
|
onClick?: (e?: React.MouseEvent) => void;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
onToggle?: (activated: boolean) => void;
|
|
12
|
+
activated?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type Elements = [
|
|
16
|
+
'menuItem',
|
|
17
|
+
'selectedItem',
|
|
18
|
+
'itemLabel',
|
|
19
|
+
'itemIcon',
|
|
20
|
+
'leadingIcon',
|
|
21
|
+
'trailingIcon',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export type MenuItemInterface = ActionOrLink<Props> & {
|
|
25
|
+
states: {
|
|
26
|
+
isActive: boolean;
|
|
25
27
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'menuItem',
|
|
29
|
-
'selectedItem',
|
|
30
|
-
'itemLabel',
|
|
31
|
-
'itemIcon',
|
|
32
|
-
'leadingIcon',
|
|
33
|
-
'trailingIcon',
|
|
34
|
-
];
|
|
35
|
-
}
|
|
28
|
+
elements: Elements;
|
|
29
|
+
};
|
|
@@ -3,7 +3,6 @@ export type MenuStates = Record<string, any>;
|
|
|
3
3
|
export interface MenuProps {
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
selected?: string | number | (string | number)[];
|
|
6
|
-
onItemSelect?: (value: string | number) => void;
|
|
7
6
|
className?: string;
|
|
8
7
|
variant?: 'standard' | 'vibrant';
|
|
9
8
|
// options prop REMOVED as requested by user ("options passed as children")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IconButton } from '../components/IconButton';
|
|
3
3
|
import { Icon } from '../icon';
|
|
4
|
+
import { MenuItemInterface } from './menu-item.interface';
|
|
4
5
|
|
|
5
6
|
export type TextFieldVariant = 'filled' | 'outlined';
|
|
6
7
|
|
|
@@ -22,14 +23,12 @@ type Props = {
|
|
|
22
23
|
id?: string;
|
|
23
24
|
style?: React.CSSProperties;
|
|
24
25
|
variant?: TextFieldVariant;
|
|
25
|
-
options?: Array<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
type?: 'divider' | 'headline';
|
|
32
|
-
}>;
|
|
26
|
+
options?: Array<
|
|
27
|
+
{
|
|
28
|
+
value: string | number;
|
|
29
|
+
type?: 'divider' | 'headline';
|
|
30
|
+
} & MenuItemInterface['props']
|
|
31
|
+
>;
|
|
33
32
|
type?: 'text' | 'password' | 'number' | 'date' | 'select';
|
|
34
33
|
autoComplete?: 'on' | 'off' | string;
|
|
35
34
|
autoFocus?: boolean;
|
|
@@ -9,31 +9,23 @@ import { MenuItemInterface } from '../interfaces/menu-item.interface';
|
|
|
9
9
|
const menuItemConfig: ClassNameComponent<MenuItemInterface> = ({
|
|
10
10
|
variant,
|
|
11
11
|
disabled,
|
|
12
|
-
|
|
12
|
+
isActive,
|
|
13
13
|
}) => ({
|
|
14
14
|
menuItem: classNames(
|
|
15
|
-
'group/menu-item overflow-hidden flex items-center h-12 px-3 cursor-pointer outline-none select-none shrink-0 ',
|
|
15
|
+
'group/menu-item text-start overflow-hidden flex items-center h-12 px-3 cursor-pointer outline-none select-none shrink-0 ',
|
|
16
16
|
'text-label-large',
|
|
17
17
|
'transition-colors duration-200',
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
'rounded-xl': !selected,
|
|
21
|
-
},
|
|
18
|
+
'rounded-xl',
|
|
19
|
+
|
|
22
20
|
{
|
|
23
21
|
'text-on-surface': !variant || variant === 'standard',
|
|
24
22
|
// 'hover:bg-on-surface/[0.08] focus:bg-on-surface/[0.12]': !props?.variant || props.variant === 'standard', // Handled by State
|
|
25
23
|
// 'hover:bg-on-tertiary-container/[0.08] focus:bg-on-tertiary-container/[0.12]': props?.variant === 'vibrant', // Handled by State
|
|
26
24
|
'opacity-38 pointer-events-none': disabled,
|
|
27
25
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// 'hover:bg-secondary-container/[0.8]',
|
|
32
|
-
'[&_.menu-item-icon]:text-inherit',
|
|
33
|
-
{
|
|
34
|
-
// For vibrant, selected state
|
|
35
|
-
'!bg-on-tertiary-container/[0.12]': variant === 'vibrant',
|
|
36
|
-
},
|
|
26
|
+
(variant === 'vibrant' || isActive) && [
|
|
27
|
+
'bg-secondary-container text-on-secondary-container',
|
|
28
|
+
],
|
|
37
29
|
),
|
|
38
30
|
itemLabel: classNames('flex-1 truncate'),
|
|
39
31
|
itemIcon: classNames(
|