@agility/plenum-ui 2.2.8 → 2.3.0
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/dist/index.d.ts +16 -30
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/tailwind.css +99 -26
- package/dist/types/stories/atoms/index.d.ts +3 -3
- package/dist/types/stories/atoms/loaders/Loader.d.ts +2 -0
- package/dist/types/stories/atoms/loaders/index.d.ts +2 -3
- package/dist/types/stories/index.d.ts +3 -3
- package/dist/types/stories/molecules/inputs/select/Select.d.ts +6 -1
- package/local.sh +1 -1
- package/package.json +1 -1
- package/stories/atoms/index.ts +1 -3
- package/stories/atoms/loaders/Loader.stories.ts +7 -7
- package/stories/atoms/loaders/Loader.tsx +11 -3
- package/stories/atoms/loaders/index.ts +3 -4
- package/stories/index.ts +0 -4
- package/stories/molecules/inputs/select/Select.stories.tsx +49 -3
- package/stories/molecules/inputs/select/Select.tsx +128 -42
- package/tailwind.config.js +78 -0
- package/dist/types/stories/atoms/loaders/NProgress/RadialProgress.d.ts +0 -11
- package/dist/types/stories/atoms/loaders/NProgress/index.d.ts +0 -3
- package/stories/atoms/loaders/NProgress/RadialProgress.stories.tsx +0 -19
- package/stories/atoms/loaders/NProgress/RadialProgress.tsx +0 -74
- package/stories/atoms/loaders/NProgress/index.ts +0 -3
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
1
|
+
import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
import InputLabel from "@/stories/molecules/inputs/InputLabel";
|
|
3
|
+
import { DynamicIcon } from "@/stories/atoms/icons/DynamicIcon";
|
|
3
4
|
import { useId } from "@/utils/useId";
|
|
4
5
|
import { default as cn } from "classnames";
|
|
5
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
Combobox as HeadlessCombobox,
|
|
8
|
+
ComboboxInput,
|
|
9
|
+
ComboboxButton,
|
|
10
|
+
ComboboxOptions,
|
|
11
|
+
ComboboxOption
|
|
12
|
+
} from "@headlessui/react";
|
|
13
|
+
import { Paragraph } from "@/stories/atoms/Typography/Paragraph";
|
|
6
14
|
|
|
7
15
|
export interface ISimpleSelectOptions {
|
|
8
16
|
label: string;
|
|
9
17
|
value: string;
|
|
18
|
+
emoji?: string;
|
|
19
|
+
description?: string;
|
|
10
20
|
}
|
|
21
|
+
|
|
11
22
|
export interface ISelectProps {
|
|
12
23
|
/** Label */
|
|
13
24
|
label?: string;
|
|
@@ -17,7 +28,7 @@ export interface ISelectProps {
|
|
|
17
28
|
name?: string;
|
|
18
29
|
/** List of options to display in the select menu */
|
|
19
30
|
options: ISimpleSelectOptions[];
|
|
20
|
-
/**
|
|
31
|
+
/** Called with the selected option's value string */
|
|
21
32
|
onChange?(value: string): void;
|
|
22
33
|
/** Select disabled state */
|
|
23
34
|
isDisabled?: boolean;
|
|
@@ -30,7 +41,11 @@ export interface ISelectProps {
|
|
|
30
41
|
onFocus?: () => void;
|
|
31
42
|
onBlur?: () => void;
|
|
32
43
|
message?: string;
|
|
44
|
+
inputRef?: React.RefObject<HTMLInputElement>;
|
|
45
|
+
placeholder?: string;
|
|
46
|
+
dropdownMaxHeight?: number;
|
|
33
47
|
}
|
|
48
|
+
|
|
34
49
|
const Select: React.FC<ISelectProps> = ({
|
|
35
50
|
label,
|
|
36
51
|
id,
|
|
@@ -44,57 +59,128 @@ const Select: React.FC<ISelectProps> = ({
|
|
|
44
59
|
className,
|
|
45
60
|
onFocus,
|
|
46
61
|
onBlur,
|
|
47
|
-
message
|
|
62
|
+
message,
|
|
63
|
+
inputRef,
|
|
64
|
+
placeholder = "Select",
|
|
65
|
+
dropdownMaxHeight = 240
|
|
48
66
|
}) => {
|
|
49
|
-
const [selectedOption, setSelectedOption] = useState<string>(value || options[0].value);
|
|
50
67
|
const uniqueID = useId();
|
|
51
68
|
if (!id) id = `select-${uniqueID}`;
|
|
52
69
|
if (!name) name = id;
|
|
53
70
|
|
|
71
|
+
const findOption = (val?: string) => options.find((o) => o.value === val) ?? null;
|
|
72
|
+
|
|
73
|
+
const [selectedOption, setSelectedOption] = useState<ISimpleSelectOptions | null>(findOption(value));
|
|
74
|
+
|
|
54
75
|
useEffect(() => {
|
|
55
|
-
|
|
56
|
-
setSelectedOption(value);
|
|
57
|
-
}
|
|
76
|
+
setSelectedOption(findOption(value));
|
|
58
77
|
}, [value]);
|
|
59
78
|
|
|
60
|
-
const handleChange = (
|
|
61
|
-
|
|
62
|
-
typeof onChange
|
|
63
|
-
|
|
79
|
+
const handleChange = (option: ISimpleSelectOptions | null) => {
|
|
80
|
+
setSelectedOption(option);
|
|
81
|
+
if (option && typeof onChange === "function") {
|
|
82
|
+
onChange(option.value);
|
|
83
|
+
}
|
|
64
84
|
};
|
|
65
|
-
|
|
85
|
+
|
|
86
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
87
|
+
const [containerWidth, setContainerWidth] = useState<number | undefined>();
|
|
88
|
+
|
|
89
|
+
useLayoutEffect(() => {
|
|
90
|
+
const el = containerRef.current;
|
|
91
|
+
if (!el) return;
|
|
92
|
+
const observer = new ResizeObserver(([entry]) => setContainerWidth(entry.contentRect.width));
|
|
93
|
+
observer.observe(el);
|
|
94
|
+
return () => observer.disconnect();
|
|
95
|
+
}, []);
|
|
96
|
+
|
|
97
|
+
const wrapperStyle = cn(className, "w-full", "group", { "opacity-50 pointer-events-none": isDisabled });
|
|
98
|
+
|
|
66
99
|
return (
|
|
67
100
|
<div className={wrapperStyle}>
|
|
68
|
-
{label && <InputLabel
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
{label && <InputLabel id={`${id}-label`} label={label} isRequired={isRequired} />}
|
|
102
|
+
|
|
103
|
+
<HeadlessCombobox value={selectedOption} onChange={handleChange} disabled={isDisabled} immediate by="value">
|
|
104
|
+
<div ref={containerRef} className="relative w-full">
|
|
105
|
+
<div
|
|
106
|
+
className={cn(
|
|
107
|
+
"relative w-full cursor-default overflow-hidden rounded border bg-white text-left shadow-sm",
|
|
108
|
+
"focus-within:border-primary-800 focus-within:ring-1 focus-within:ring-primary-800",
|
|
109
|
+
{ "border-red-500": isError, "border-gray-300": !isError }
|
|
110
|
+
)}
|
|
111
|
+
>
|
|
112
|
+
<ComboboxInput
|
|
113
|
+
id={id}
|
|
114
|
+
name={name}
|
|
115
|
+
ref={inputRef}
|
|
116
|
+
readOnly
|
|
117
|
+
displayValue={(option: ISimpleSelectOptions | null) => (option ? option.label : "")}
|
|
118
|
+
placeholder={placeholder}
|
|
119
|
+
onFocus={onFocus}
|
|
120
|
+
onBlur={onBlur}
|
|
121
|
+
className={cn(
|
|
122
|
+
"w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-700",
|
|
123
|
+
"placeholder:text-gray-400",
|
|
124
|
+
"focus:outline-none focus:ring-0",
|
|
125
|
+
"bg-transparent cursor-default"
|
|
126
|
+
)}
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
<ComboboxButton className="absolute inset-y-0 right-0 flex items-center pr-3">
|
|
130
|
+
{({ open }) => (
|
|
131
|
+
<DynamicIcon
|
|
132
|
+
icon="IconChevronDown"
|
|
133
|
+
className={cn("h-4 w-4 text-gray-400 transition-transform", { "rotate-180": open })}
|
|
134
|
+
aria-hidden="true"
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</ComboboxButton>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<ComboboxOptions
|
|
141
|
+
anchor="bottom start"
|
|
142
|
+
style={
|
|
143
|
+
{
|
|
144
|
+
"--anchor-max-height": `${dropdownMaxHeight}px`,
|
|
145
|
+
minWidth: containerWidth
|
|
146
|
+
} as React.CSSProperties
|
|
147
|
+
}
|
|
148
|
+
className={cn(
|
|
149
|
+
"z-[9999] overflow-auto rounded bg-white py-1",
|
|
150
|
+
"text-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none",
|
|
151
|
+
"[--anchor-gap:8px]"
|
|
152
|
+
)}
|
|
153
|
+
>
|
|
154
|
+
{options.map((option) => (
|
|
155
|
+
<ComboboxOption
|
|
156
|
+
key={option.value}
|
|
157
|
+
value={option}
|
|
158
|
+
className={({ focus }) =>
|
|
159
|
+
cn(
|
|
160
|
+
"relative cursor-default select-none mx-xxsm rounded",
|
|
161
|
+
focus ? "bg-gray-100 text-gray-900" : "text-gray-700"
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
>
|
|
165
|
+
{({ selected }) => (
|
|
166
|
+
<div className="py-xxsm px-sm flex items-center gap-xsm">
|
|
167
|
+
<Paragraph size="md">{option.label}</Paragraph>
|
|
168
|
+
{option.description ? (
|
|
169
|
+
<Paragraph size="md" className="text-neutral-500">{option.description}</Paragraph>
|
|
170
|
+
) : null}
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
</ComboboxOption>
|
|
174
|
+
))}
|
|
175
|
+
</ComboboxOptions>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
{message && (
|
|
179
|
+
<Paragraph size="md" className={isError ? "text-red-600" : "text-gray-500 pt-xxsm"}>
|
|
180
|
+
{message}
|
|
181
|
+
</Paragraph>
|
|
78
182
|
)}
|
|
79
|
-
|
|
80
|
-
disabled={isDisabled}
|
|
81
|
-
value={selectedOption}
|
|
82
|
-
onFocus={onFocus}
|
|
83
|
-
onBlur={onBlur}
|
|
84
|
-
>
|
|
85
|
-
{options.map(({ value, label }) => {
|
|
86
|
-
return (
|
|
87
|
-
<option key={value} value={value}>
|
|
88
|
-
{label}
|
|
89
|
-
</option>
|
|
90
|
-
);
|
|
91
|
-
})}
|
|
92
|
-
</select>
|
|
93
|
-
{message && (
|
|
94
|
-
<Paragraph size="md" className={isError ? "text-red-600" : "text-gray-500"}>
|
|
95
|
-
{message}
|
|
96
|
-
</Paragraph>
|
|
97
|
-
)}
|
|
183
|
+
</HeadlessCombobox>
|
|
98
184
|
</div>
|
|
99
185
|
);
|
|
100
186
|
};
|
package/tailwind.config.js
CHANGED
|
@@ -52,6 +52,72 @@ module.exports = {
|
|
|
52
52
|
header: "max-content 1fr 1fr"
|
|
53
53
|
},
|
|
54
54
|
colors: {
|
|
55
|
+
"neutral-50": "#F7F7F7",
|
|
56
|
+
"neutral-100": "#F2F2F2",
|
|
57
|
+
"neutral-200": "#E5E7EB",
|
|
58
|
+
"neutral-300": "#D1D5DB",
|
|
59
|
+
"neutral-400": "#9CA3aF",
|
|
60
|
+
"neutral-500": "#6B7280",
|
|
61
|
+
"neutral-600": "#4B5563",
|
|
62
|
+
"neutral-700": "#374151",
|
|
63
|
+
"neutral-800": "#1F2937",
|
|
64
|
+
"neutral-900": "#111827",
|
|
65
|
+
|
|
66
|
+
"primary-50": "#F7F7F7",
|
|
67
|
+
"primary-100": "#EDE9FE",
|
|
68
|
+
"primary-200": "#DDD6FE",
|
|
69
|
+
"primary-300": "#C4B5FD",
|
|
70
|
+
"primary-400": "#A78BFA",
|
|
71
|
+
"primary-500": "#8B5CF6",
|
|
72
|
+
"primary-600": "#7C3AED",
|
|
73
|
+
"primary-700": "#6D28D9",
|
|
74
|
+
"primary-800": "#5B21B6",
|
|
75
|
+
"primary-900": "#4C1D95",
|
|
76
|
+
|
|
77
|
+
"secondary-50": "#FFFAEA",
|
|
78
|
+
"secondary-100": "#FFF5D4",
|
|
79
|
+
"secondary-200": "#FFEAA9",
|
|
80
|
+
"secondary-300": "#FFE07E",
|
|
81
|
+
"secondary-400": "#FFD553",
|
|
82
|
+
"secondary-500": "#FFCB28",
|
|
83
|
+
"secondary-600": "#F2C126",
|
|
84
|
+
"secondary-700": "#D9AD22",
|
|
85
|
+
"secondary-800": "#BF981E",
|
|
86
|
+
"secondary-900": "#997A18",
|
|
87
|
+
|
|
88
|
+
"success-50": "#ECFDF5",
|
|
89
|
+
"success-100": "#D1FAE5",
|
|
90
|
+
"success-200": "#A7F3D0",
|
|
91
|
+
"success-300": "#6EE7B7",
|
|
92
|
+
"success-400": "#34D399",
|
|
93
|
+
"success-500": "#10B981",
|
|
94
|
+
"success-600": "#059669",
|
|
95
|
+
"success-700": "#047857",
|
|
96
|
+
"success-800": "#065F46",
|
|
97
|
+
"success-900": "#064E3B",
|
|
98
|
+
|
|
99
|
+
"warning-50": "#FFF7ED",
|
|
100
|
+
"warning-100": "#FFEDD5",
|
|
101
|
+
"warning-200": "#FED7AA",
|
|
102
|
+
"warning-300": "#FDBA74",
|
|
103
|
+
"warning-400": "#FB923C",
|
|
104
|
+
"warning-500": "#F97316",
|
|
105
|
+
"warning-600": "#EA580C",
|
|
106
|
+
"warning-700": "#C2410C",
|
|
107
|
+
"warning-800": "#9A3412",
|
|
108
|
+
"warning-900": "#7C2D12",
|
|
109
|
+
|
|
110
|
+
"error-50": "#FEF2F2",
|
|
111
|
+
"error-100": "#FEE2E2",
|
|
112
|
+
"error-200": "#FECACA",
|
|
113
|
+
"error-300": "#FCA5A5",
|
|
114
|
+
"error-400": "#F87171",
|
|
115
|
+
"error-500": "#EF4444",
|
|
116
|
+
"error-600": "#DC2626",
|
|
117
|
+
"error-700": "#B91C1C",
|
|
118
|
+
"error-800": "#991B1B",
|
|
119
|
+
"error-900": "#7F1D1D",
|
|
120
|
+
|
|
55
121
|
"transparent-white-05": "rgba(255, 255, 255, 0.05)",
|
|
56
122
|
"transparent-white-10": "rgba(255, 255, 255, 0.1)",
|
|
57
123
|
"transparent-white-20": "rgba(255, 255, 255, 0.2)",
|
|
@@ -287,6 +353,18 @@ module.exports = {
|
|
|
287
353
|
transitionProperty: {
|
|
288
354
|
left: "left",
|
|
289
355
|
height: "height"
|
|
356
|
+
},
|
|
357
|
+
spacing: {
|
|
358
|
+
xxsm: "4px",
|
|
359
|
+
xsm: "8px",
|
|
360
|
+
sm: "12px",
|
|
361
|
+
md: "16px",
|
|
362
|
+
lg: "20px",
|
|
363
|
+
xlg: "24px",
|
|
364
|
+
xxlg: "28px",
|
|
365
|
+
hg: "32px",
|
|
366
|
+
xhg: "40px",
|
|
367
|
+
xxhg: "80px"
|
|
290
368
|
}
|
|
291
369
|
}
|
|
292
370
|
},
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
export interface IRadialProgressProps extends React.PropsWithChildren {
|
|
3
|
-
/** Percentage value to display */
|
|
4
|
-
inputValue: number;
|
|
5
|
-
/** Radius for the circle - Max value of 100 */
|
|
6
|
-
radius: number;
|
|
7
|
-
/** Additional classnames */
|
|
8
|
-
className?: string;
|
|
9
|
-
}
|
|
10
|
-
declare const RadialProgress: React.FC<IRadialProgressProps>;
|
|
11
|
-
export default RadialProgress;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
import RadialProgress from "./RadialProgress"
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof RadialProgress> = {
|
|
5
|
-
title: "Design System/atoms/Loaders/NProgress/RadialProgress",
|
|
6
|
-
component: RadialProgress
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
type Story = StoryObj<typeof RadialProgress>
|
|
10
|
-
|
|
11
|
-
export const DefaultRadialProgress: Story = {
|
|
12
|
-
args: {
|
|
13
|
-
inputValue: 33,
|
|
14
|
-
radius: 20,
|
|
15
|
-
children: <></>
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default meta
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from "react"
|
|
2
|
-
import { default as cn } from "classnames"
|
|
3
|
-
export interface IRadialProgressProps extends React.PropsWithChildren {
|
|
4
|
-
/** Percentage value to display */
|
|
5
|
-
inputValue: number
|
|
6
|
-
/** Radius for the circle - Max value of 100 */
|
|
7
|
-
radius: number
|
|
8
|
-
/** Additional classnames */
|
|
9
|
-
className?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const RadialProgress: React.FC<IRadialProgressProps> = ({
|
|
13
|
-
inputValue,
|
|
14
|
-
radius,
|
|
15
|
-
children,
|
|
16
|
-
className,
|
|
17
|
-
}) => {
|
|
18
|
-
const r = radius / 2
|
|
19
|
-
|
|
20
|
-
if (inputValue < 0) {
|
|
21
|
-
inputValue = 0
|
|
22
|
-
}
|
|
23
|
-
if (inputValue > 100) {
|
|
24
|
-
inputValue = 100
|
|
25
|
-
}
|
|
26
|
-
if (radius < 0) {
|
|
27
|
-
radius = 0
|
|
28
|
-
}
|
|
29
|
-
if (radius > 100) {
|
|
30
|
-
radius = 100
|
|
31
|
-
}
|
|
32
|
-
const drawPercentage = useMemo(() => {
|
|
33
|
-
const roundCircum = Math.round(2 * r * Math.PI)
|
|
34
|
-
return (inputValue * roundCircum) / 50
|
|
35
|
-
}, [inputValue, r])
|
|
36
|
-
|
|
37
|
-
const xyPos = (radius + 2) * -1
|
|
38
|
-
const viewPortXY = (radius + 2) * 2
|
|
39
|
-
return (
|
|
40
|
-
<div
|
|
41
|
-
className={cn(`overflow-visible`, className && className)}
|
|
42
|
-
style={{ height: `${viewPortXY}px`, width: `${viewPortXY}px` }}
|
|
43
|
-
>
|
|
44
|
-
<svg
|
|
45
|
-
viewBox={`${xyPos} ${xyPos} ${viewPortXY} ${viewPortXY}`}
|
|
46
|
-
data-percent={drawPercentage}
|
|
47
|
-
fill="none"
|
|
48
|
-
>
|
|
49
|
-
<circle
|
|
50
|
-
className="-rotate-90 stroke-gray-200 stroke-1"
|
|
51
|
-
cx={0}
|
|
52
|
-
cy={0}
|
|
53
|
-
r={radius}
|
|
54
|
-
></circle>
|
|
55
|
-
<circle
|
|
56
|
-
strokeDasharray={`${drawPercentage} 999`}
|
|
57
|
-
className="m-1 -rotate-90 stroke-purple-600 stroke-1 transition-all"
|
|
58
|
-
cx={0}
|
|
59
|
-
cy={0}
|
|
60
|
-
r={radius}
|
|
61
|
-
></circle>
|
|
62
|
-
</svg>
|
|
63
|
-
<div
|
|
64
|
-
className={cn(
|
|
65
|
-
`h-[${viewPortXY}px] w-[${viewPortXY}px] absolute inset-0 flex items-center justify-center overflow-hidden `
|
|
66
|
-
)}
|
|
67
|
-
>
|
|
68
|
-
{children}
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export default RadialProgress
|