Skip to content

Commit d0d97b7

Browse files
authored
Merge pull request #77 from kleros/chore/build-configuration
Chore/build configuration
2 parents 1c79ca2 + 14d2014 commit d0d97b7

File tree

11 files changed

+559
-119
lines changed

11 files changed

+559
-119
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ If you wish the use the library's tailwind theme variables in your tailwind app.
8383

8484
```css
8585
@import tailwindcss @import
86-
"../../../node_modules/@kleros/ui-components-library/dist/theme/theme.css";
86+
"../../../node_modules/@kleros/ui-components-library/dist/assets/theme.css";
8787
```
8888

8989
You can find the available theme variables [here](src/styles/theme.css).

package.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"name": "@kleros/ui-components-library",
3-
"version": "3.1.2",
3+
"version": "3.2.3",
44
"description": "UI components library which implements the Kleros design system.",
55
"source": "./src/lib/index.ts",
6-
"main": "./dist/esm/ui-components-library.js",
7-
"module": "./dist/esm/ui-components-library.js",
6+
"main": "./dist/index.js",
7+
"module": "./dist/index.js",
88
"types": "./dist/ui-components-library.d.ts",
9-
"style": "./dist/esm/ui-components-library.css",
9+
"style": "./dist/assets/index.css",
1010
"isLibrary": true,
1111
"type": "module",
1212
"browserslist": "> 0.5%, last 2 versions, not dead",
@@ -15,15 +15,17 @@
1515
"license": "MIT",
1616
"exports": {
1717
".": {
18-
"import": "./dist/esm/ui-components-library.js",
18+
"import": "./dist/index.js",
1919
"types": "./dist/ui-components-library.d.ts"
2020
},
21-
"./style.css": "./dist/esm/ui-components-library.css",
22-
"./theme.css": "./dist/theme/theme.css"
21+
"./style.css": "./dist/assets/index.css",
22+
"./theme.css": "./dist/assets/theme.css"
2323
},
24+
"sideEffects": [
25+
"**/*.css"
26+
],
2427
"scripts": {
25-
"build:theme": "vite build --config vite.config.theme.js",
26-
"build": "vite build && yarn build:theme",
28+
"build": "vite build",
2729
"build-storybook": "storybook build",
2830
"check-style": "eslint 'src/**/*.{ts,tsx}'",
2931
"check-types": "tsc --noEmit",
@@ -49,6 +51,7 @@
4951
"@storybook/react-vite": "^8.6.4",
5052
"@storybook/test": "^8.6.4",
5153
"@tailwindcss/postcss": "^4.0.11",
54+
"@tailwindcss/vite": "^4.1.4",
5255
"@types/node": "^22.13.10",
5356
"@types/react": "^18.0.9",
5457
"@types/react-dom": "^18.0.3",
@@ -64,6 +67,7 @@
6467
"eslint-plugin-react-hooks": "^5.2.0",
6568
"eslint-plugin-security": "^3.0.1",
6669
"eslint-plugin-storybook": "^0.11.4",
70+
"glob": "^11.0.1",
6771
"globals": "^16.0.0",
6872
"husky": "^7.0.0",
6973
"lint-staged": "^12.1.2",
@@ -74,6 +78,8 @@
7478
"tailwindcss": "^4.0.11",
7579
"typescript": "^5.8.2",
7680
"vite": "^6.2.1",
81+
"vite-plugin-dts": "^4.5.3",
82+
"vite-plugin-lib-inject-css": "^2.2.2",
7783
"vite-plugin-svgr": "^4.3.0"
7884
},
7985
"peerDependencies": {
@@ -85,7 +91,6 @@
8591
},
8692
"dependencies": {
8793
"@internationalized/date": "^3.7.0",
88-
"@tailwindcss/vite": "^4.0.12",
8994
"bignumber.js": "^9.1.2",
9095
"clsx": "^2.1.1",
9196
"react": "^18.0.0",
@@ -96,8 +101,7 @@
96101
"simplebar-react": "^2.3.6",
97102
"tailwind-merge": "^3.0.2",
98103
"tailwindcss-react-aria-components": "^2.0.0",
99-
"usehooks-ts": "^2.9.1",
100-
"vite-plugin-dts": "^4.5.3"
104+
"usehooks-ts": "^2.9.1"
101105
},
102106
"lint-staged": {
103107
"*.js": "eslint --cache --fix",

src/assets/svgs/drag-and-drop.svg

Lines changed: 3 additions & 0 deletions
Loading

src/assets/svgs/trash.svg

Lines changed: 3 additions & 0 deletions
Loading

src/lib/breadcrumb.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Button } from "react-aria-components";
44
import { clsx } from "clsx";
55

66
interface BreadcrumbProps {
7-
items: { text: string; value: any }[];
7+
items: { text: React.ReactNode; value: any }[];
88
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
99
callback?: Function;
1010
clickable?: boolean;

src/lib/draggable-list/index.tsx

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, { useEffect } from "react";
2+
import { useListData } from "react-stately";
3+
import {
4+
Button,
5+
ListBox,
6+
ListBoxItem,
7+
useDragAndDrop,
8+
type ListBoxItemProps,
9+
type ListBoxProps,
10+
type DragAndDropOptions,
11+
} from "react-aria-components";
12+
import { cn } from "../../utils";
13+
import DragAndDropIcon from "../../assets/svgs/drag-and-drop.svg";
14+
import Trash from "../../assets/svgs/trash.svg";
15+
import clsx from "clsx";
16+
17+
type ListItem = {
18+
id: string | number;
19+
name: string;
20+
value: any;
21+
};
22+
interface IDraggableList
23+
extends Omit<
24+
ListBoxProps<ListBoxItemProps>,
25+
| "items"
26+
| "selectionMode"
27+
| "dragAndDropHooks"
28+
| "selectionBehavior"
29+
| "orientation"
30+
| "onSelectionChange"
31+
> {
32+
items: ListItem[];
33+
/** Returns the updated list after a delete or move operation. */
34+
updateCallback?: (updatedItems: ListItem[]) => void;
35+
/** Returns the selected item. */
36+
selectionCallback?: (list: ListItem) => void;
37+
/** Display custom preview for the item being dragged. */
38+
renderDragPreview?: DragAndDropOptions["renderDragPreview"];
39+
}
40+
41+
/** List that allows users to reorder items via drag and drop */
42+
function DraggableList({
43+
items,
44+
updateCallback,
45+
selectionCallback,
46+
className,
47+
renderDragPreview,
48+
...props
49+
}: Readonly<IDraggableList>) {
50+
const list = useListData({
51+
initialItems: items,
52+
});
53+
54+
useEffect(() => {
55+
if (!updateCallback) return;
56+
updateCallback(list.items);
57+
}, [list, updateCallback, items]);
58+
59+
const { dragAndDropHooks } = useDragAndDrop({
60+
getItems: (keys) =>
61+
[...keys].map((key) => ({ "text/plain": list.getItem(key)!.name })),
62+
getAllowedDropOperations: () => ["move"],
63+
onReorder(e) {
64+
if (e.target.dropPosition === "before") {
65+
list.moveBefore(e.target.key, e.keys);
66+
} else if (e.target.dropPosition === "after") {
67+
list.moveAfter(e.target.key, e.keys);
68+
}
69+
},
70+
renderDragPreview,
71+
});
72+
73+
return (
74+
<ListBox
75+
{...props}
76+
aria-label={props["aria-label"] ?? "Reorderable list"}
77+
selectionMode="single"
78+
items={list.items}
79+
dragAndDropHooks={dragAndDropHooks}
80+
onSelectionChange={(keys) => {
81+
const keyArr = Array.from(keys);
82+
const selectedItem = list.getItem(keyArr[0]);
83+
84+
if (selectionCallback && selectedItem) selectionCallback(selectedItem);
85+
}}
86+
className={cn(
87+
"bg-klerosUIComponentsLightBackground rounded-base border-klerosUIComponentsStroke border",
88+
"w-95.5 py-4",
89+
"[&_div]:data-drop-target:outline-klerosUIComponentsPrimaryBlue [&_div]:data-drop-target:outline",
90+
className,
91+
)}
92+
>
93+
{(item) => (
94+
<ListBoxItem
95+
textValue={item.name}
96+
className={({ isHovered, isDragging, isSelected }) =>
97+
cn(
98+
"h-11.25 w-full cursor-pointer border-l-3 border-l-transparent",
99+
"flex items-center gap-4 px-4",
100+
"focus-visible:outline-klerosUIComponentsPrimaryBlue focus-visible:outline",
101+
(isHovered || isSelected) && "bg-klerosUIComponentsMediumBlue",
102+
isSelected && "border-l-klerosUIComponentsPrimaryBlue",
103+
isDragging && "cursor-grabbing opacity-60",
104+
)
105+
}
106+
>
107+
{({ isHovered }) => (
108+
<>
109+
<DragAndDropIcon className="size-4 cursor-grab" />
110+
<span className="text-klerosUIComponentsPrimaryText flex-1 text-base">
111+
{item.name}
112+
</span>
113+
{isHovered ? (
114+
<Button
115+
className={"cursor-pointer hover:scale-105"}
116+
onPress={() => {
117+
list.remove(item.id);
118+
}}
119+
>
120+
{({ isHovered: isButtonHovered }) => (
121+
<Trash
122+
className={clsx(
123+
"ease-ease size-4 transition",
124+
isButtonHovered &&
125+
"[&_path]:fill-klerosUIComponentsPrimaryBlue",
126+
)}
127+
/>
128+
)}
129+
</Button>
130+
) : null}
131+
</>
132+
)}
133+
</ListBoxItem>
134+
)}
135+
</ListBox>
136+
);
137+
}
138+
139+
export default DraggableList;

src/lib/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,5 @@ export { default as Tooltip } from "../lib/tooltip";
4949
export { default as ScrollbarContainer } from "../lib/scrollbar";
5050

5151
export { default as Copiable } from "../lib/copiable";
52+
53+
export { default as DraggableList } from "../lib/draggable-list";
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import type { Meta, StoryObj } from "@storybook/react";
3+
4+
import { IPreviewArgs } from "./utils";
5+
6+
import DraggableList from "../lib/draggable-list";
7+
8+
const meta = {
9+
component: DraggableList,
10+
title: "Draggable List",
11+
tags: ["autodocs"],
12+
} satisfies Meta<typeof DraggableList>;
13+
14+
export default meta;
15+
16+
type Story = StoryObj<typeof meta> & IPreviewArgs;
17+
18+
export const Default: Story = {
19+
args: {
20+
themeUI: "light",
21+
backgroundUI: "light",
22+
items: [
23+
{ id: 1, name: "Illustrator", value: "" },
24+
{ id: 2, name: "Premiere", value: "" },
25+
{ id: 3, name: "Acrobat", value: "" },
26+
],
27+
},
28+
render: (args) => {
29+
return <DraggableList {...args} />;
30+
},
31+
};
32+
33+
export const CustomDragPreview: Story = {
34+
args: {
35+
themeUI: "light",
36+
backgroundUI: "light",
37+
items: [
38+
{ id: 1, name: "Illustrator", value: "" },
39+
{ id: 2, name: "Premiere", value: "" },
40+
{ id: 3, name: "Acrobat", value: "" },
41+
],
42+
renderDragPreview: (items) => (
43+
<div className="rounded-base bg-klerosUIComponentsPrimaryBlue px-4 py-2">
44+
<span className="text-klerosUIComponentsPrimaryText text-base">
45+
{items[0]["text/plain"]}
46+
</span>
47+
</div>
48+
),
49+
},
50+
render: (args) => {
51+
return <DraggableList {...args} />;
52+
},
53+
};

vite.config.theme.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

vite.config.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import { resolve } from "path";
21
import { defineConfig } from "vite";
32
import react from "@vitejs/plugin-react";
43
import svgr from "vite-plugin-svgr";
54
// eslint-disable-next-line import/no-unresolved
65
import tailwindcss from "@tailwindcss/vite";
76
import dts from "vite-plugin-dts";
7+
import { libInjectCss } from "vite-plugin-lib-inject-css";
8+
import { extname, relative, resolve } from "path";
9+
import { fileURLToPath } from "node:url";
10+
import { glob } from "glob";
811

912
export default defineConfig({
1013
build: {
@@ -17,9 +20,27 @@ export default defineConfig({
1720
// make sure to externalize deps that shouldn't be bundled
1821
// into your library
1922
external: ["react", "react-dom"],
23+
input: Object.fromEntries(
24+
glob
25+
.sync("src/lib/**/*.{ts,tsx}", {
26+
ignore: ["src/lib/**/*.d.ts"],
27+
})
28+
.map((file) => [
29+
// The name of the entry point
30+
// lib/nested/foo.ts becomes nested/foo
31+
relative(
32+
"src/lib",
33+
file.slice(0, file.length - extname(file).length),
34+
),
35+
// The absolute path to the entry file
36+
// lib/nested/foo.ts becomes /project/lib/nested/foo.ts
37+
fileURLToPath(new URL(file, import.meta.url)),
38+
]),
39+
),
2040
output: {
21-
dir: "dist/esm",
22-
preserveModules: true,
41+
assetFileNames: "assets/[name][extname]",
42+
entryFileNames: "[name].js",
43+
2344
// Provide global variables to use in the UMD build
2445
// for externalized deps
2546
globals: {
@@ -35,6 +56,7 @@ export default defineConfig({
3556
}),
3657
tailwindcss(),
3758
react(),
59+
libInjectCss(),
3860
dts({
3961
insertTypesEntry: true,
4062
include: ["src/lib", "src/global.d.ts"],

0 commit comments

Comments
 (0)