Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates and fixes #26

Merged
merged 19 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions packages/core/src/components/badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { isNumber, isObject, mergeRefs } from "@react-fabric/utilities";
import { isNil, isNumber, isObject, mergeRefs } from "@react-fabric/utilities";
import classNames from "classnames";
import { cloneElement, useMemo } from "react";
import {
Expand Down Expand Up @@ -101,10 +101,12 @@ export const Badge = ({
...rest
}: BadgeProps) => {
const label = useMemo(() => {
if (isNumber(value) && max && value > max) {
return `${max}+`;
if (!isNil(value)) {
if (isNumber(value) && max && value > max) {
return `${max}+`;
}
return `${value}`;
}
return `${value}`;
}, [value, max]);

const innerRef = useMemo(
Expand All @@ -127,22 +129,24 @@ export const Badge = ({
...rest,
ref: innerRef,
})}
<div
data-ref="badge"
data-ping={ping}
data-placement={placement}
className={classNames(
classes.badge,
className,
"inline-block p-px min-w-2 min-h-2 text-center select-none rounded-full leading-none z-5 pointer-events-none",
forButton && !placement ? "relative" : "absolute",
)}
>
{label && <span className="p-1">{label}</span>}
{icon && (
<Icon icon={icon} bg={iconBg} color={iconColor} rtlFlip={rtlFlip} />
)}
</div>
{(!!ping || label) && (
<div
data-ref="badge"
data-ping={ping}
data-placement={placement}
className={classNames(
classes.badge,
className,
"inline-block p-px min-w-2 min-h-2 text-center select-none rounded-full leading-none z-5 pointer-events-none",
forButton && !placement ? "relative" : "absolute",
)}
>
{label && <span className="p-1">{label}</span>}
{icon && (
<Icon icon={icon} bg={iconBg} color={iconColor} rtlFlip={rtlFlip} />
)}
</div>
)}
</div>
);
};
7 changes: 5 additions & 2 deletions packages/core/src/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ export interface BaseProps
*/
hotKey?: string;

stopPropagation?: boolean;

onMouseOut?: MouseEventHandler;
onMouseOver?: MouseEventHandler;
onMouseMove?: MouseEventHandler;
Expand Down Expand Up @@ -175,6 +177,7 @@ export const Button = <Tag extends React.ElementType = "button">({
spinOnHover,
onClick,
actionMessage,
stopPropagation,
type = "button",
hotKey,
showActionDone,
Expand All @@ -191,7 +194,7 @@ export const Button = <Tag extends React.ElementType = "button">({
const clickHandler = useCallback(
(e: React.MouseEvent) => {
setBusy(true);
// e.stopPropagation();
stopPropagation && e.stopPropagation();
const ret = onClick?.(e);
void Promise.resolve(ret).then((b) => {
setBusy(false);
Expand All @@ -200,7 +203,7 @@ export const Button = <Tag extends React.ElementType = "button">({
}
});
},
[onClick, disabled, actionMessage, showActionDoneEvent],
[onClick, disabled, actionMessage, showActionDoneEvent, stopPropagation],
);

/** ***************** reset done state on timeout *******************/
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/components/callout/Callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,19 @@ import {
type AriaProps,
type ChildrenProp,
type ColorType,
type CssProp,
type PaletteType,
type TestProps,
} from "../../types";
import { CoreIcons } from "../../types/icons";
import { getBgClass, getBorderClass, getColorClass } from "../../utils";
import { Icon } from "../icon/Icon";

export interface CalloutProps extends AriaProps, ChildrenProp, TestProps {
export interface CalloutProps
extends AriaProps,
ChildrenProp,
CssProp,
TestProps {
/**
* callout color
*/
Expand Down Expand Up @@ -69,11 +74,13 @@ export const Callout = ({
icon,
border,
onClose,
className,
...aria
}: CalloutProps) => {
return (
<fieldset
className={classNames(
className,
"block rounded-capped border max-w-full relative overflow-hidden mb-4",
getBgClass(color + "-50"),
getColorClass(color + "-700"),
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/components/collapsable/Collapsable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export interface CollapsableProps
* open state
*/
open?: boolean;
/**
* disable collapsable
*/
disabled?: boolean;
/**
* open handler
*/
Expand All @@ -90,6 +94,7 @@ export interface CollapsableProps

export const Collapsable = ({
ref,
disabled,
className,
bodyClassName,
headerClassName,
Expand Down Expand Up @@ -135,7 +140,7 @@ export const Collapsable = ({
headerClassName,
iconAlign === "end" ? "flex-row-reverse" : "flex-row",
)}
onClick={() => setOpenState(!openState)}
onClick={() => !disabled && setOpenState(!openState)}
>
<Icon size="1.125em" icon={openState ? iconOpen : iconClosed} rtlFlip />
<div className="flex-1 px-2">{head}</div>
Expand Down
11 changes: 9 additions & 2 deletions packages/core/src/core/aside/Aside.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@
*/

import classNames from "classnames";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
type ReactNode,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { Loading } from "../../components/animations/Animations";
import { Icon } from "../../components/icon/Icon";
import { useLayoutEffectDebugger } from "../../hooks/useEffectDebugger";
Expand All @@ -47,7 +54,7 @@ export interface AsideProps
/**
* page title
*/
title?: string;
title?: ReactNode;
/**
* align inline-end
*/
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/core/section/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/

import classNames from "classnames";
import { type ChildrenProp } from "../../types";
import { type ChildrenProp, type CssProp, type RefProp } from "../../types";
import { ErrorBoundary } from "../boundary/ErrorBoundary";
import classes from "./Section.module.css";

Expand All @@ -31,14 +31,20 @@ import classes from "./Section.module.css";
*/
export const Section = ({
children,
className,
dir,
}: ChildrenProp & { dir?: "ltr" | "rtl" }) => {
ref,
}: ChildrenProp &
CssProp &
RefProp<HTMLDivElement> & { dir?: "ltr" | "rtl" }) => {
return (
<div
data-ref="section"
dir={dir}
ref={ref}
className={classNames(
classes.section,
className,
"grid area-content overflow-hidden",
)}
>
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/overlays/alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ export const Alert = ({

<Title className="font-medium area-[title]">{title}</Title>
<p className="area-[message] py-4">{message}</p>
<div className="area-[message]">{message}</div>
<div className="flex gap-1 justify-center flex-nowrap pt-2 area-[actions]">
<div
className="contents"
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ export interface RefProp<T = HTMLElement> {
/* *********** */

// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
export type CallbackReturn<T = unknown> = void | T | Promise<T | void>;
export type CallbackReturn<T = unknown> =
| undefined
| T
| Promise<T | undefined>;

export type ReactTag = keyof JSX.IntrinsicElements | JSXElementConstructor<any>;

Expand All @@ -155,7 +158,7 @@ export type PropsOf<AsTag extends ReactTag> = AsTag extends React.ElementType

export type PolymorphicProps<AsTag extends ReactTag> = Omit<
PropsOf<AsTag>,
"children" | "as" | "className"
"children" | "as" | "className" | "onClick"
> & {
/**
* The component used for the root node.
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/typography/Abbr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import classNames from "classnames";
import { Fragment, useCallback, useMemo } from "react";
import { useMemoDebugger } from "../hooks/useEffectDebugger";
import { Tooltip, getTooltipProps } from "../overlays/tooltip/Tooltip";
import { type ChildProp, type ColorType } from "../types";
import { type ChildProp, type ColorType, type CssProp } from "../types";
import { getColor, getColorClass } from "../utils";
import classes from "./Typography.module.css";

Expand Down Expand Up @@ -64,7 +64,7 @@ const AbbrText = ({ color, children, tooltip, content }: AbbrTextProps) => {
);
};

export interface AbbrProps extends ChildProp<string> {
export interface AbbrProps extends ChildProp<string>, CssProp {
/**
* content to copy using the tooltip copy action
*/
Expand All @@ -87,6 +87,7 @@ export interface AbbrProps extends ChildProp<string> {
export const Abbr = ({
children,
abbr,
className,
renderer,
copyContent = "text",
}: AbbrProps) => {
Expand Down Expand Up @@ -148,5 +149,5 @@ export const Abbr = ({
);

/** ***************** component *******************/
return <span>{inner}</span>;
return <span className={className}>{inner}</span>;
};
3 changes: 3 additions & 0 deletions packages/core/src/typography/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

import classNames from "classnames";
import { type MouseEventHandler } from "react";
import { useMemoDebugger } from "../hooks/useEffectDebugger";
import {
type AriaProps,
Expand Down Expand Up @@ -52,6 +53,8 @@ export interface LinkProps extends ChildrenProp, CssProp, RefProp, AriaProps {
* font family
*/
family?: "sans" | "serif" | "mono";

onClick?: MouseEventHandler;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/data/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ export { Histogram } from "./histogram/Histogram";
export { JsonViewer } from "./json/JsonViewer";
export { Pagination } from "./pagination/Pagination";
export { Table } from "./table/Table";
export { type TableRef } from "./table/types";
export { TreePanel } from "./tree/TreePanel";
export { type TreeNodeType as TreeNode } from "./tree/types";
export { VirtualGallery, type VirtualGalleryRef } from "./virtual/Gallery";
export { VirtualList, type VirtualListRef } from "./virtual/List";

Expand Down
34 changes: 32 additions & 2 deletions packages/data/src/table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import { EmptyContent, Loading, useDebounce } from "@react-fabric/core";
import classNames from "classnames";
import { useMemo } from "react";
import { useImperativeHandle, useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { AddColumn } from "./AddColumn";
import { BodyCell } from "./BodyCell";
Expand All @@ -36,6 +36,7 @@ import { useTableColumns } from "./useTableColumns";
import { useVirtualTable } from "./useVirtualTable";

export const Table = <T extends KeyValue = KeyValue>({
ref,
data,
columns,
keyProperty,
Expand Down Expand Up @@ -64,6 +65,7 @@ export const Table = <T extends KeyValue = KeyValue>({
totalSize,
measureElement,
} = useVirtualTable(data, keyProperty, fireCheckChanged);
const refBody = useRef<HTMLDivElement>(null);

const wrapperStart = useMemo(
() => "bg-inherit sticky start-0 flex flex-nowrap z-1",
Expand All @@ -74,6 +76,32 @@ export const Table = <T extends KeyValue = KeyValue>({
[],
);

useImperativeHandle(
ref,
() => ({
hilight: (row: number) => {
refBody.current
?.querySelectorAll<HTMLElement>(`.datatable-row[data-hilight="true"]`)
.forEach((el) => el && (el.dataset.hilight = undefined));
const el = refBody.current?.querySelector<HTMLElement>(
`[data-row="${row}"]`,
);
el?.scrollIntoView({ behavior: "smooth", block: "center" });
el && (el.dataset.hilight = "true");
},
unhilight: () => {
refBody.current
?.querySelectorAll<HTMLElement>(`.datatable-row[data-hilight="true"]`)
.forEach((el) => el && (el.dataset.hilight = undefined));
},
scrollTo: (row: number) => {
const el = refBody.current?.querySelector(`[data-row="${row}"]`);
el?.scrollIntoView({ behavior: "smooth" });
},
}),
[],
);

return (
<TableProvider>
<div
Expand Down Expand Up @@ -116,6 +144,7 @@ export const Table = <T extends KeyValue = KeyValue>({
<div
className="area-content flex flex-col flex-nowrap"
style={{ height: totalSize() }}
ref={refBody}
>
<div style={{ height: items[0]?.start }} />
{items.map(({ index, key }) => {
Expand All @@ -124,8 +153,9 @@ export const Table = <T extends KeyValue = KeyValue>({
<div
key={key}
role="none"
data-row={index}
className={classNames(
"flex flex-nowrap",
"flex flex-nowrap datatable-row data-[hilight]:outline-1 -outline-offset-1 outline-primary-500",
index % 2 ? "bg-even" : "bg-odd",
onRowClick && "hover:bg-primary-50 active:bg-primary-100",
)}
Expand Down
Loading
Loading