@crystallize/design-system 1.11.3 → 1.11.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 +6 -0
- package/dist/index.css +28 -9
- package/dist/index.d.ts +6 -2
- package/dist/index.js +53 -36
- package/dist/index.mjs +46 -29
- package/package.json +4 -3
- package/src/action-menu/ActionMenu.stories.tsx +12 -0
- package/src/action-menu/action-menu.css +22 -3
- package/src/action-menu/action-menu.test.tsx +53 -0
- package/src/action-menu/action-menu.tsx +23 -3
- package/src/button/button.test.tsx +22 -0
- package/src/dropdown-menu/dropdown-menu-root.tsx +12 -10
- package/src/dropdown-menu/dropdown-menu.css +1 -1
- package/src/popover/index.ts +1 -0
- package/src/popover/popover-close.tsx +18 -0
- package/src/popover/popover.css +11 -0
- package/src/popover/popover.stories.tsx +48 -0
- package/src/popover/popover.tsx +45 -0
package/CHANGELOG.md
CHANGED
package/dist/index.css
CHANGED
|
@@ -640,6 +640,9 @@ button {
|
|
|
640
640
|
.h-full {
|
|
641
641
|
height: 100%;
|
|
642
642
|
}
|
|
643
|
+
.w-1\/2 {
|
|
644
|
+
width: 50%;
|
|
645
|
+
}
|
|
643
646
|
.w-4 {
|
|
644
647
|
width: 1rem;
|
|
645
648
|
}
|
|
@@ -878,6 +881,9 @@ button {
|
|
|
878
881
|
padding-top: 0.5rem;
|
|
879
882
|
padding-bottom: 0.5rem;
|
|
880
883
|
}
|
|
884
|
+
.pt-14 {
|
|
885
|
+
padding-top: 3.5rem;
|
|
886
|
+
}
|
|
881
887
|
.text-center {
|
|
882
888
|
text-align: center;
|
|
883
889
|
}
|
|
@@ -1199,8 +1205,6 @@ button {
|
|
|
1199
1205
|
/* src/action-menu/action-menu.css */
|
|
1200
1206
|
.c-action-menu {
|
|
1201
1207
|
display: flex;
|
|
1202
|
-
height: 2rem;
|
|
1203
|
-
width: 2rem;
|
|
1204
1208
|
flex-shrink: 0;
|
|
1205
1209
|
--tw-rotate: 0deg;
|
|
1206
1210
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
@@ -1212,7 +1216,6 @@ button {
|
|
|
1212
1216
|
border-radius: 0.375rem;
|
|
1213
1217
|
border-style: none;
|
|
1214
1218
|
background-color: transparent;
|
|
1215
|
-
padding: 0.25rem;
|
|
1216
1219
|
outline-offset: -1px;
|
|
1217
1220
|
transition-property:
|
|
1218
1221
|
color,
|
|
@@ -1230,8 +1233,6 @@ button {
|
|
|
1230
1233
|
transition-duration: 150ms;
|
|
1231
1234
|
}
|
|
1232
1235
|
.c-action-menu-dot {
|
|
1233
|
-
height: 4px;
|
|
1234
|
-
width: 4px;
|
|
1235
1236
|
border-radius: 9999px;
|
|
1236
1237
|
background-color: rgb(var(--c-color-gray));
|
|
1237
1238
|
}
|
|
@@ -1261,15 +1262,33 @@ button {
|
|
|
1261
1262
|
--tw-bg-opacity: 1;
|
|
1262
1263
|
background-color: rgb(var(--c-color-purple-100-800) / var(--tw-bg-opacity));
|
|
1263
1264
|
}
|
|
1265
|
+
.c-action-menu-xs {
|
|
1266
|
+
height: 1.5rem;
|
|
1267
|
+
width: 1.5rem;
|
|
1268
|
+
padding: 0.125rem;
|
|
1269
|
+
}
|
|
1270
|
+
.c-action-menu-xs .c-action-menu-dot {
|
|
1271
|
+
height: 0.125rem;
|
|
1272
|
+
width: 0.125rem;
|
|
1273
|
+
}
|
|
1274
|
+
.c-action-menu-sm {
|
|
1275
|
+
height: 2rem;
|
|
1276
|
+
width: 2rem;
|
|
1277
|
+
padding: 0.25rem;
|
|
1278
|
+
}
|
|
1279
|
+
.c-action-menu-sm .c-action-menu-dot {
|
|
1280
|
+
height: 0.25rem;
|
|
1281
|
+
width: 0.25rem;
|
|
1282
|
+
}
|
|
1264
1283
|
.c-action-menu-item {
|
|
1265
1284
|
display: flex;
|
|
1266
1285
|
cursor: pointer;
|
|
1267
1286
|
align-items: center;
|
|
1268
1287
|
gap: 0.5rem;
|
|
1269
|
-
padding-top: 0.625rem;
|
|
1270
|
-
padding-bottom: 0.625rem;
|
|
1271
1288
|
padding-left: 1.25rem;
|
|
1272
1289
|
padding-right: 1.25rem;
|
|
1290
|
+
padding-top: 0.625rem;
|
|
1291
|
+
padding-bottom: 0.625rem;
|
|
1273
1292
|
font-family:
|
|
1274
1293
|
Roboto,
|
|
1275
1294
|
ui-sans-serif,
|
|
@@ -1400,12 +1419,12 @@ button {
|
|
|
1400
1419
|
outline-offset: 2px;
|
|
1401
1420
|
}
|
|
1402
1421
|
.c-dropdown-menu-item:first-child {
|
|
1403
|
-
border-top-right-radius: 0.25rem;
|
|
1404
1422
|
border-top-left-radius: 0.25rem;
|
|
1423
|
+
border-top-right-radius: 0.25rem;
|
|
1405
1424
|
}
|
|
1406
1425
|
.c-dropdown-menu-item:last-child {
|
|
1407
|
-
border-bottom-right-radius: 0.25rem;
|
|
1408
1426
|
border-bottom-left-radius: 0.25rem;
|
|
1427
|
+
border-bottom-right-radius: 0.25rem;
|
|
1409
1428
|
}
|
|
1410
1429
|
|
|
1411
1430
|
/* src/avatar/avatar.css */
|
package/dist/index.d.ts
CHANGED
|
@@ -19,11 +19,15 @@ type ItemProps = HTMLAttributes<HTMLLIElement> & {
|
|
|
19
19
|
};
|
|
20
20
|
declare function Item({ children, className, onSelect }: ItemProps): JSX.Element;
|
|
21
21
|
|
|
22
|
-
type
|
|
22
|
+
type ButtonStylesProps$1 = VariantProps<typeof buttonStyles$2>;
|
|
23
|
+
declare const buttonStyles$2: (props?: ({
|
|
24
|
+
size?: "xs" | "sm" | null | undefined;
|
|
25
|
+
} & class_variance_authority_dist_types.ClassProp) | undefined) => string;
|
|
26
|
+
type ActionMenuProps = ButtonStylesProps$1 & {
|
|
23
27
|
children: ReactNode;
|
|
24
28
|
tabIndex?: number;
|
|
25
29
|
};
|
|
26
|
-
declare function ActionMenu({ children, tabIndex }: ActionMenuProps): JSX.Element;
|
|
30
|
+
declare function ActionMenu({ children, tabIndex, size }: ActionMenuProps): JSX.Element;
|
|
27
31
|
declare namespace ActionMenu {
|
|
28
32
|
var Item: typeof Item;
|
|
29
33
|
var Separator: typeof Separator;
|
package/dist/index.js
CHANGED
|
@@ -251,6 +251,9 @@ function Card({ children, className, variant, ...delegated }) {
|
|
|
251
251
|
// src/card/index.ts
|
|
252
252
|
var cardToken = "c-card";
|
|
253
253
|
|
|
254
|
+
// src/action-menu/action-menu.tsx
|
|
255
|
+
var import_class_variance_authority7 = require("class-variance-authority");
|
|
256
|
+
|
|
254
257
|
// src/dropdown-menu/index.ts
|
|
255
258
|
var import_react_dropdown_menu = require("@radix-ui/react-dropdown-menu");
|
|
256
259
|
|
|
@@ -282,7 +285,7 @@ var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
|
282
285
|
function DropdownMenuRoot({
|
|
283
286
|
children,
|
|
284
287
|
content,
|
|
285
|
-
alignContent = "
|
|
288
|
+
alignContent = "center",
|
|
286
289
|
disabled,
|
|
287
290
|
onOpenChange,
|
|
288
291
|
...delegated
|
|
@@ -295,12 +298,14 @@ function DropdownMenuRoot({
|
|
|
295
298
|
asChild: true,
|
|
296
299
|
children
|
|
297
300
|
}),
|
|
298
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive3.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
301
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive3.Portal, {
|
|
302
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive3.Content, {
|
|
303
|
+
align: alignContent,
|
|
304
|
+
sideOffset: 5,
|
|
305
|
+
className: "c-dropdown-menu-content",
|
|
306
|
+
...delegated,
|
|
307
|
+
children: content
|
|
308
|
+
})
|
|
304
309
|
})
|
|
305
310
|
]
|
|
306
311
|
});
|
|
@@ -338,15 +343,27 @@ function Separator2({ className }) {
|
|
|
338
343
|
|
|
339
344
|
// src/action-menu/action-menu.tsx
|
|
340
345
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
341
|
-
|
|
346
|
+
var buttonStyles2 = (0, import_class_variance_authority7.cva)("c-action-menu", {
|
|
347
|
+
variants: {
|
|
348
|
+
size: {
|
|
349
|
+
xs: "c-action-menu-xs",
|
|
350
|
+
sm: "c-action-menu-sm"
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
defaultVariants: {
|
|
354
|
+
size: "sm"
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
function ActionMenu({ children, tabIndex, size }) {
|
|
342
358
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenu.Root, {
|
|
343
359
|
content: children,
|
|
344
360
|
alignContent: "center",
|
|
345
361
|
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", {
|
|
362
|
+
"aria-label": "more options",
|
|
363
|
+
className: buttonStyles2({ size }),
|
|
364
|
+
"data-testid": "action-menu-button",
|
|
346
365
|
tabIndex,
|
|
347
366
|
type: "button",
|
|
348
|
-
className: "c-action-menu",
|
|
349
|
-
"aria-label": "more options",
|
|
350
367
|
children: [
|
|
351
368
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", {
|
|
352
369
|
className: "sr-only",
|
|
@@ -370,7 +387,7 @@ ActionMenu.Separator = Separator2;
|
|
|
370
387
|
|
|
371
388
|
// src/avatar/avatar.tsx
|
|
372
389
|
var import_react3 = require("react");
|
|
373
|
-
var
|
|
390
|
+
var import_class_variance_authority8 = require("class-variance-authority");
|
|
374
391
|
|
|
375
392
|
// src/avatar/get-initials.ts
|
|
376
393
|
var getInitials = (name) => {
|
|
@@ -381,7 +398,7 @@ var getInitials = (name) => {
|
|
|
381
398
|
|
|
382
399
|
// src/avatar/avatar.tsx
|
|
383
400
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
384
|
-
var avatarClassName = (0,
|
|
401
|
+
var avatarClassName = (0, import_class_variance_authority8.cva)(["c-avatar"], {
|
|
385
402
|
variants: {
|
|
386
403
|
size: {
|
|
387
404
|
md: "c-avatar-md",
|
|
@@ -443,7 +460,7 @@ var destroyFns = [];
|
|
|
443
460
|
|
|
444
461
|
// src/dialog/dialog.tsx
|
|
445
462
|
var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"));
|
|
446
|
-
var
|
|
463
|
+
var import_class_variance_authority9 = require("class-variance-authority");
|
|
447
464
|
|
|
448
465
|
// src/iconography/add.tsx
|
|
449
466
|
var import_react5 = require("react");
|
|
@@ -2972,7 +2989,7 @@ var IconMap = {
|
|
|
2972
2989
|
info: Icon.Info,
|
|
2973
2990
|
warning: Icon.Warning
|
|
2974
2991
|
};
|
|
2975
|
-
var dialogContentStyles = (0,
|
|
2992
|
+
var dialogContentStyles = (0, import_class_variance_authority9.cva)("c-dialog", {
|
|
2976
2993
|
variants: {
|
|
2977
2994
|
withIcon: {
|
|
2978
2995
|
true: "c-dialog-with-icon"
|
|
@@ -3022,7 +3039,7 @@ function DialogContent({ children, closable = true, type, className, container,
|
|
|
3022
3039
|
}
|
|
3023
3040
|
function DialogTitle({ className, ...delegated }) {
|
|
3024
3041
|
return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(DialogPrimitive.Title, {
|
|
3025
|
-
className: (0,
|
|
3042
|
+
className: (0, import_class_variance_authority9.cx)("c-dialog-title", className),
|
|
3026
3043
|
...delegated
|
|
3027
3044
|
});
|
|
3028
3045
|
}
|
|
@@ -3263,9 +3280,9 @@ function destroyAll() {
|
|
|
3263
3280
|
|
|
3264
3281
|
// src/icon-button/icon-button.tsx
|
|
3265
3282
|
var import_react54 = require("react");
|
|
3266
|
-
var
|
|
3283
|
+
var import_class_variance_authority10 = require("class-variance-authority");
|
|
3267
3284
|
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
3268
|
-
var
|
|
3285
|
+
var buttonStyles3 = (0, import_class_variance_authority10.cva)(["c-icon-button"], {
|
|
3269
3286
|
variants: {
|
|
3270
3287
|
variant: {
|
|
3271
3288
|
default: "",
|
|
@@ -3289,7 +3306,7 @@ var IconButton = (0, import_react54.forwardRef)(
|
|
|
3289
3306
|
return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", {
|
|
3290
3307
|
ref,
|
|
3291
3308
|
type,
|
|
3292
|
-
className:
|
|
3309
|
+
className: buttonStyles3({ size, variant, className }),
|
|
3293
3310
|
...delegated,
|
|
3294
3311
|
children
|
|
3295
3312
|
});
|
|
@@ -3299,9 +3316,9 @@ IconButton.displayName = "Button";
|
|
|
3299
3316
|
|
|
3300
3317
|
// src/inline-radio/inline-radio.tsx
|
|
3301
3318
|
var RadioGroupPrimitive = __toESM(require("@radix-ui/react-radio-group"));
|
|
3302
|
-
var
|
|
3319
|
+
var import_class_variance_authority11 = require("class-variance-authority");
|
|
3303
3320
|
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
3304
|
-
var inlineRadioGroupStyles = (0,
|
|
3321
|
+
var inlineRadioGroupStyles = (0, import_class_variance_authority11.cva)("c-inline-radio-group", {
|
|
3305
3322
|
variants: {
|
|
3306
3323
|
size: {
|
|
3307
3324
|
xs: "c-inline-radio-group-xs",
|
|
@@ -3323,7 +3340,7 @@ function InlineRadioGroup({ size, className, ...delegated }) {
|
|
|
3323
3340
|
function InlineRadioItem({ children, className, ...delegated }) {
|
|
3324
3341
|
return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RadioGroupPrimitive.Item, {
|
|
3325
3342
|
...delegated,
|
|
3326
|
-
className: (0,
|
|
3343
|
+
className: (0, import_class_variance_authority11.cx)("c-inline-radio", className),
|
|
3327
3344
|
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RadioGroupPrimitive.Indicator, {
|
|
3328
3345
|
forceMount: true,
|
|
3329
3346
|
children
|
|
@@ -3337,13 +3354,13 @@ var InlineRadio = {
|
|
|
3337
3354
|
|
|
3338
3355
|
// src/input-with-label/input-with-label.tsx
|
|
3339
3356
|
var import_react58 = require("react");
|
|
3340
|
-
var
|
|
3357
|
+
var import_class_variance_authority14 = require("class-variance-authority");
|
|
3341
3358
|
|
|
3342
3359
|
// src/input/input.tsx
|
|
3343
|
-
var
|
|
3360
|
+
var import_class_variance_authority12 = require("class-variance-authority");
|
|
3344
3361
|
var import_react55 = require("react");
|
|
3345
3362
|
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
3346
|
-
var inputStyles = (0,
|
|
3363
|
+
var inputStyles = (0, import_class_variance_authority12.cva)(["c-input"], {
|
|
3347
3364
|
variants: {},
|
|
3348
3365
|
defaultVariants: {}
|
|
3349
3366
|
});
|
|
@@ -3359,12 +3376,12 @@ Input.displayName = "Input";
|
|
|
3359
3376
|
|
|
3360
3377
|
// src/label/label.tsx
|
|
3361
3378
|
var import_react56 = require("react");
|
|
3362
|
-
var
|
|
3379
|
+
var import_class_variance_authority13 = require("class-variance-authority");
|
|
3363
3380
|
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
3364
3381
|
var Label2 = (0, import_react56.forwardRef)(({ className, ...delegated }, ref) => {
|
|
3365
3382
|
return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("label", {
|
|
3366
3383
|
ref,
|
|
3367
|
-
className: (0,
|
|
3384
|
+
className: (0, import_class_variance_authority13.cx)("c-label", className),
|
|
3368
3385
|
...delegated
|
|
3369
3386
|
});
|
|
3370
3387
|
});
|
|
@@ -3393,7 +3410,7 @@ var Triangle = (0, import_react57.forwardRef)((delegated, ref) => {
|
|
|
3393
3410
|
|
|
3394
3411
|
// src/input-with-label/input-with-label.tsx
|
|
3395
3412
|
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
3396
|
-
var inputWithLabelStyles = (0,
|
|
3413
|
+
var inputWithLabelStyles = (0, import_class_variance_authority14.cva)(["c-input-with-label"], {
|
|
3397
3414
|
variants: {
|
|
3398
3415
|
variant: {
|
|
3399
3416
|
default: "",
|
|
@@ -3420,7 +3437,7 @@ var InputWithLabel = (0, import_react58.forwardRef)(
|
|
|
3420
3437
|
className: "c-input-with-label-input-wrap",
|
|
3421
3438
|
children: [
|
|
3422
3439
|
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Input, {
|
|
3423
|
-
className: (0,
|
|
3440
|
+
className: (0, import_class_variance_authority14.cx)("c-input-with-label-input", className),
|
|
3424
3441
|
ref,
|
|
3425
3442
|
id,
|
|
3426
3443
|
...delegated
|
|
@@ -3441,11 +3458,11 @@ InputWithLabel.displayName = "InputWithLabel";
|
|
|
3441
3458
|
|
|
3442
3459
|
// src/progress/progress.tsx
|
|
3443
3460
|
var ProgressPrimitives = __toESM(require("@radix-ui/react-progress"));
|
|
3444
|
-
var
|
|
3461
|
+
var import_class_variance_authority15 = require("class-variance-authority");
|
|
3445
3462
|
var import_jsx_runtime70 = require("react/jsx-runtime");
|
|
3446
3463
|
function Progress({ className, value }) {
|
|
3447
3464
|
return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(ProgressPrimitives.Root, {
|
|
3448
|
-
className: (0,
|
|
3465
|
+
className: (0, import_class_variance_authority15.cx)(className, "c-progress-root"),
|
|
3449
3466
|
value,
|
|
3450
3467
|
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(ProgressPrimitives.Indicator, {
|
|
3451
3468
|
className: "c-progress-indicator",
|
|
@@ -3494,9 +3511,9 @@ SelectItem.displayName = "SelectItem";
|
|
|
3494
3511
|
// src/select/select-root.tsx
|
|
3495
3512
|
var import_react60 = require("react");
|
|
3496
3513
|
var SelectPrimitives2 = __toESM(require("@radix-ui/react-select"));
|
|
3497
|
-
var
|
|
3514
|
+
var import_class_variance_authority16 = require("class-variance-authority");
|
|
3498
3515
|
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
3499
|
-
var selectTriggerStyles = (0,
|
|
3516
|
+
var selectTriggerStyles = (0, import_class_variance_authority16.cva)("c-select-trigger", {
|
|
3500
3517
|
variants: {
|
|
3501
3518
|
size: {
|
|
3502
3519
|
xs: "c-select-trigger-xs",
|
|
@@ -3556,12 +3573,12 @@ var Select = {
|
|
|
3556
3573
|
|
|
3557
3574
|
// src/slider/slider.tsx
|
|
3558
3575
|
var SliderPrimitive = __toESM(require("@radix-ui/react-slider"));
|
|
3559
|
-
var
|
|
3576
|
+
var import_class_variance_authority17 = require("class-variance-authority");
|
|
3560
3577
|
var import_react61 = require("react");
|
|
3561
3578
|
var import_jsx_runtime74 = require("react/jsx-runtime");
|
|
3562
3579
|
var Slider = (0, import_react61.forwardRef)(({ className, transparentRange, ...delegated }, ref) => {
|
|
3563
3580
|
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(SliderPrimitive.Root, {
|
|
3564
|
-
className: (0,
|
|
3581
|
+
className: (0, import_class_variance_authority17.cx)("c-slider-root", className),
|
|
3565
3582
|
ref,
|
|
3566
3583
|
...delegated,
|
|
3567
3584
|
children: [
|
|
@@ -3579,9 +3596,9 @@ var Slider = (0, import_react61.forwardRef)(({ className, transparentRange, ...d
|
|
|
3579
3596
|
});
|
|
3580
3597
|
|
|
3581
3598
|
// src/tag/tag.tsx
|
|
3582
|
-
var
|
|
3599
|
+
var import_class_variance_authority18 = require("class-variance-authority");
|
|
3583
3600
|
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
3584
|
-
var tagStyles = (0,
|
|
3601
|
+
var tagStyles = (0, import_class_variance_authority18.cva)("c-tag", {
|
|
3585
3602
|
variants: {
|
|
3586
3603
|
variant: {
|
|
3587
3604
|
default: "",
|
package/dist/index.mjs
CHANGED
|
@@ -191,8 +191,11 @@ function Card({ children, className, variant, ...delegated }) {
|
|
|
191
191
|
// src/card/index.ts
|
|
192
192
|
var cardToken = "c-card";
|
|
193
193
|
|
|
194
|
+
// src/action-menu/action-menu.tsx
|
|
195
|
+
import { cva as cva3 } from "class-variance-authority";
|
|
196
|
+
|
|
194
197
|
// src/dropdown-menu/index.ts
|
|
195
|
-
import { Portal, Separator } from "@radix-ui/react-dropdown-menu";
|
|
198
|
+
import { Portal as Portal2, Separator } from "@radix-ui/react-dropdown-menu";
|
|
196
199
|
|
|
197
200
|
// src/dropdown-menu/dropdown-menu-item.tsx
|
|
198
201
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
@@ -222,7 +225,7 @@ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
222
225
|
function DropdownMenuRoot({
|
|
223
226
|
children,
|
|
224
227
|
content,
|
|
225
|
-
alignContent = "
|
|
228
|
+
alignContent = "center",
|
|
226
229
|
disabled,
|
|
227
230
|
onOpenChange,
|
|
228
231
|
...delegated
|
|
@@ -235,12 +238,14 @@ function DropdownMenuRoot({
|
|
|
235
238
|
asChild: true,
|
|
236
239
|
children
|
|
237
240
|
}),
|
|
238
|
-
/* @__PURE__ */ jsx6(DropdownMenuPrimitive3.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
/* @__PURE__ */ jsx6(DropdownMenuPrimitive3.Portal, {
|
|
242
|
+
children: /* @__PURE__ */ jsx6(DropdownMenuPrimitive3.Content, {
|
|
243
|
+
align: alignContent,
|
|
244
|
+
sideOffset: 5,
|
|
245
|
+
className: "c-dropdown-menu-content",
|
|
246
|
+
...delegated,
|
|
247
|
+
children: content
|
|
248
|
+
})
|
|
244
249
|
})
|
|
245
250
|
]
|
|
246
251
|
});
|
|
@@ -252,7 +257,7 @@ var DropdownMenu = {
|
|
|
252
257
|
Item: DropdownMenuItem,
|
|
253
258
|
Label: DropdownMenuLabel,
|
|
254
259
|
Separator,
|
|
255
|
-
Portal
|
|
260
|
+
Portal: Portal2
|
|
256
261
|
};
|
|
257
262
|
|
|
258
263
|
// src/action-menu/action-item.tsx
|
|
@@ -278,15 +283,27 @@ function Separator2({ className }) {
|
|
|
278
283
|
|
|
279
284
|
// src/action-menu/action-menu.tsx
|
|
280
285
|
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
281
|
-
|
|
286
|
+
var buttonStyles2 = cva3("c-action-menu", {
|
|
287
|
+
variants: {
|
|
288
|
+
size: {
|
|
289
|
+
xs: "c-action-menu-xs",
|
|
290
|
+
sm: "c-action-menu-sm"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
defaultVariants: {
|
|
294
|
+
size: "sm"
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
function ActionMenu({ children, tabIndex, size }) {
|
|
282
298
|
return /* @__PURE__ */ jsx9(DropdownMenu.Root, {
|
|
283
299
|
content: children,
|
|
284
300
|
alignContent: "center",
|
|
285
301
|
children: /* @__PURE__ */ jsxs4("button", {
|
|
302
|
+
"aria-label": "more options",
|
|
303
|
+
className: buttonStyles2({ size }),
|
|
304
|
+
"data-testid": "action-menu-button",
|
|
286
305
|
tabIndex,
|
|
287
306
|
type: "button",
|
|
288
|
-
className: "c-action-menu",
|
|
289
|
-
"aria-label": "more options",
|
|
290
307
|
children: [
|
|
291
308
|
/* @__PURE__ */ jsx9("span", {
|
|
292
309
|
className: "sr-only",
|
|
@@ -310,7 +327,7 @@ ActionMenu.Separator = Separator2;
|
|
|
310
327
|
|
|
311
328
|
// src/avatar/avatar.tsx
|
|
312
329
|
import { forwardRef as forwardRef3 } from "react";
|
|
313
|
-
import { cva as
|
|
330
|
+
import { cva as cva4 } from "class-variance-authority";
|
|
314
331
|
|
|
315
332
|
// src/avatar/get-initials.ts
|
|
316
333
|
var getInitials = (name) => {
|
|
@@ -321,7 +338,7 @@ var getInitials = (name) => {
|
|
|
321
338
|
|
|
322
339
|
// src/avatar/avatar.tsx
|
|
323
340
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
324
|
-
var avatarClassName =
|
|
341
|
+
var avatarClassName = cva4(["c-avatar"], {
|
|
325
342
|
variants: {
|
|
326
343
|
size: {
|
|
327
344
|
md: "c-avatar-md",
|
|
@@ -383,7 +400,7 @@ var destroyFns = [];
|
|
|
383
400
|
|
|
384
401
|
// src/dialog/dialog.tsx
|
|
385
402
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
386
|
-
import { cva as
|
|
403
|
+
import { cva as cva5, cx as cx5 } from "class-variance-authority";
|
|
387
404
|
|
|
388
405
|
// src/iconography/add.tsx
|
|
389
406
|
import { forwardRef as forwardRef5 } from "react";
|
|
@@ -2912,7 +2929,7 @@ var IconMap = {
|
|
|
2912
2929
|
info: Icon.Info,
|
|
2913
2930
|
warning: Icon.Warning
|
|
2914
2931
|
};
|
|
2915
|
-
var dialogContentStyles =
|
|
2932
|
+
var dialogContentStyles = cva5("c-dialog", {
|
|
2916
2933
|
variants: {
|
|
2917
2934
|
withIcon: {
|
|
2918
2935
|
true: "c-dialog-with-icon"
|
|
@@ -3203,9 +3220,9 @@ function destroyAll() {
|
|
|
3203
3220
|
|
|
3204
3221
|
// src/icon-button/icon-button.tsx
|
|
3205
3222
|
import { forwardRef as forwardRef54 } from "react";
|
|
3206
|
-
import { cva as
|
|
3223
|
+
import { cva as cva6 } from "class-variance-authority";
|
|
3207
3224
|
import { jsx as jsx64 } from "react/jsx-runtime";
|
|
3208
|
-
var
|
|
3225
|
+
var buttonStyles3 = cva6(["c-icon-button"], {
|
|
3209
3226
|
variants: {
|
|
3210
3227
|
variant: {
|
|
3211
3228
|
default: "",
|
|
@@ -3229,7 +3246,7 @@ var IconButton = forwardRef54(
|
|
|
3229
3246
|
return /* @__PURE__ */ jsx64("button", {
|
|
3230
3247
|
ref,
|
|
3231
3248
|
type,
|
|
3232
|
-
className:
|
|
3249
|
+
className: buttonStyles3({ size, variant, className }),
|
|
3233
3250
|
...delegated,
|
|
3234
3251
|
children
|
|
3235
3252
|
});
|
|
@@ -3239,9 +3256,9 @@ IconButton.displayName = "Button";
|
|
|
3239
3256
|
|
|
3240
3257
|
// src/inline-radio/inline-radio.tsx
|
|
3241
3258
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
3242
|
-
import { cx as cx6, cva as
|
|
3259
|
+
import { cx as cx6, cva as cva7 } from "class-variance-authority";
|
|
3243
3260
|
import { jsx as jsx65 } from "react/jsx-runtime";
|
|
3244
|
-
var inlineRadioGroupStyles =
|
|
3261
|
+
var inlineRadioGroupStyles = cva7("c-inline-radio-group", {
|
|
3245
3262
|
variants: {
|
|
3246
3263
|
size: {
|
|
3247
3264
|
xs: "c-inline-radio-group-xs",
|
|
@@ -3277,13 +3294,13 @@ var InlineRadio = {
|
|
|
3277
3294
|
|
|
3278
3295
|
// src/input-with-label/input-with-label.tsx
|
|
3279
3296
|
import { forwardRef as forwardRef58 } from "react";
|
|
3280
|
-
import { cva as
|
|
3297
|
+
import { cva as cva9, cx as cx8 } from "class-variance-authority";
|
|
3281
3298
|
|
|
3282
3299
|
// src/input/input.tsx
|
|
3283
|
-
import { cva as
|
|
3300
|
+
import { cva as cva8 } from "class-variance-authority";
|
|
3284
3301
|
import { forwardRef as forwardRef55 } from "react";
|
|
3285
3302
|
import { jsx as jsx66 } from "react/jsx-runtime";
|
|
3286
|
-
var inputStyles =
|
|
3303
|
+
var inputStyles = cva8(["c-input"], {
|
|
3287
3304
|
variants: {},
|
|
3288
3305
|
defaultVariants: {}
|
|
3289
3306
|
});
|
|
@@ -3333,7 +3350,7 @@ var Triangle = forwardRef57((delegated, ref) => {
|
|
|
3333
3350
|
|
|
3334
3351
|
// src/input-with-label/input-with-label.tsx
|
|
3335
3352
|
import { Fragment, jsx as jsx69, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
3336
|
-
var inputWithLabelStyles =
|
|
3353
|
+
var inputWithLabelStyles = cva9(["c-input-with-label"], {
|
|
3337
3354
|
variants: {
|
|
3338
3355
|
variant: {
|
|
3339
3356
|
default: "",
|
|
@@ -3434,9 +3451,9 @@ SelectItem.displayName = "SelectItem";
|
|
|
3434
3451
|
// src/select/select-root.tsx
|
|
3435
3452
|
import { forwardRef as forwardRef60 } from "react";
|
|
3436
3453
|
import * as SelectPrimitives2 from "@radix-ui/react-select";
|
|
3437
|
-
import { cva as
|
|
3454
|
+
import { cva as cva10 } from "class-variance-authority";
|
|
3438
3455
|
import { jsx as jsx73, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
3439
|
-
var selectTriggerStyles =
|
|
3456
|
+
var selectTriggerStyles = cva10("c-select-trigger", {
|
|
3440
3457
|
variants: {
|
|
3441
3458
|
size: {
|
|
3442
3459
|
xs: "c-select-trigger-xs",
|
|
@@ -3519,9 +3536,9 @@ var Slider = forwardRef61(({ className, transparentRange, ...delegated }, ref) =
|
|
|
3519
3536
|
});
|
|
3520
3537
|
|
|
3521
3538
|
// src/tag/tag.tsx
|
|
3522
|
-
import { cva as
|
|
3539
|
+
import { cva as cva11 } from "class-variance-authority";
|
|
3523
3540
|
import { jsx as jsx75 } from "react/jsx-runtime";
|
|
3524
|
-
var tagStyles =
|
|
3541
|
+
var tagStyles = cva11("c-tag", {
|
|
3525
3542
|
variants: {
|
|
3526
3543
|
variant: {
|
|
3527
3544
|
default: "",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crystallize/design-system",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"types": "./dist/index.d.ts",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@radix-ui/react-checkbox": "1.0.1",
|
|
41
41
|
"@radix-ui/react-dialog": "1.0.2",
|
|
42
42
|
"@radix-ui/react-dropdown-menu": "2.0.1",
|
|
43
|
+
"@radix-ui/react-popover": "1.0.0",
|
|
43
44
|
"@radix-ui/react-progress": "^1.0.1",
|
|
44
45
|
"@radix-ui/react-radio-group": "1.1.0",
|
|
45
46
|
"@radix-ui/react-select": "1.1.2",
|
|
@@ -88,8 +89,8 @@
|
|
|
88
89
|
"tailwindcss": "^3.3.0",
|
|
89
90
|
"tsup": "^6.5.0",
|
|
90
91
|
"typescript": "^4.9.4",
|
|
91
|
-
"vite": "^4.
|
|
92
|
-
"vitest": "^0.
|
|
92
|
+
"vite": "^4.2.1",
|
|
93
|
+
"vitest": "^0.30.1",
|
|
93
94
|
"tsconfig": "0.0.0"
|
|
94
95
|
},
|
|
95
96
|
"keywords": [
|
|
@@ -23,3 +23,15 @@ export const Default: Story = {
|
|
|
23
23
|
</ActionMenu>
|
|
24
24
|
),
|
|
25
25
|
};
|
|
26
|
+
|
|
27
|
+
export const XS: Story = {
|
|
28
|
+
args: {},
|
|
29
|
+
render: () => (
|
|
30
|
+
<ActionMenu size="xs">
|
|
31
|
+
<ActionMenu.Item onSelect={() => console.warn('Download')}>Download</ActionMenu.Item>
|
|
32
|
+
<ActionMenu.Item className="danger" onSelect={() => console.warn('Delete')}>
|
|
33
|
+
Delete
|
|
34
|
+
</ActionMenu.Item>
|
|
35
|
+
</ActionMenu>
|
|
36
|
+
),
|
|
37
|
+
};
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
.c-action-menu {
|
|
2
|
-
@apply flex
|
|
2
|
+
@apply flex shrink-0 rotate-0 cursor-pointer flex-col items-center justify-center gap-[2px] rounded-md border-none bg-transparent -outline-offset-1 transition;
|
|
3
|
+
|
|
3
4
|
&-dot {
|
|
4
|
-
@apply
|
|
5
|
+
@apply rounded-full bg-gray;
|
|
5
6
|
}
|
|
7
|
+
|
|
6
8
|
&[data-state='open'],
|
|
7
9
|
[aria-expanded='true'] {
|
|
8
10
|
@apply flex-row gap-[3px];
|
|
9
11
|
}
|
|
12
|
+
|
|
10
13
|
&:focus-visible {
|
|
11
14
|
@apply outline outline-1 outline-inherit;
|
|
12
15
|
outline-color: currentColor;
|
|
@@ -21,8 +24,24 @@
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
.c-action-menu-xs {
|
|
28
|
+
@apply h-6 w-6 p-0.5;
|
|
29
|
+
|
|
30
|
+
.c-action-menu-dot {
|
|
31
|
+
@apply h-0.5 w-0.5;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.c-action-menu-sm {
|
|
36
|
+
@apply h-8 w-8 p-1;
|
|
37
|
+
|
|
38
|
+
.c-action-menu-dot {
|
|
39
|
+
@apply h-1 w-1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
24
43
|
.c-action-menu-item {
|
|
25
|
-
@apply flex cursor-pointer items-center gap-2 py-2.5
|
|
44
|
+
@apply flex cursor-pointer items-center gap-2 px-5 py-2.5 font-sans text-sm font-medium text-gray;
|
|
26
45
|
|
|
27
46
|
&:hover {
|
|
28
47
|
@apply bg-gray-50-900;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
|
|
4
|
+
import { ActionMenu } from './index';
|
|
5
|
+
|
|
6
|
+
describe('ActionMenu', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
render(
|
|
9
|
+
<ActionMenu>
|
|
10
|
+
<ActionMenu.Item onSelect={() => {}}>Delete</ActionMenu.Item>
|
|
11
|
+
</ActionMenu>,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
expect(screen.getByLabelText(/more options/i)).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('opens the menu and selects an option when clicking on an action item', async () => {
|
|
18
|
+
const onSelectOption = vi.fn();
|
|
19
|
+
const callbackThatShouldNotBeExecuted = vi.fn();
|
|
20
|
+
const user = userEvent.setup();
|
|
21
|
+
|
|
22
|
+
const touchableProps = { onSelect: onSelectOption, onClick: onSelectOption };
|
|
23
|
+
const touchablePropsThatShouldNotBeCalled = {
|
|
24
|
+
onSelect: callbackThatShouldNotBeExecuted,
|
|
25
|
+
onClick: callbackThatShouldNotBeExecuted,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
render(
|
|
29
|
+
<ActionMenu>
|
|
30
|
+
<ActionMenu.Item {...touchableProps}>Add</ActionMenu.Item>
|
|
31
|
+
<ActionMenu.Item {...touchablePropsThatShouldNotBeCalled}>Delete</ActionMenu.Item>
|
|
32
|
+
</ActionMenu>,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const triggerButton = screen.getByTestId('action-menu-button') as HTMLButtonElement;
|
|
36
|
+
await user.click(triggerButton);
|
|
37
|
+
|
|
38
|
+
// The user should be able to see the dropdown menu
|
|
39
|
+
const dropdownMenu = await screen.getByRole('menu');
|
|
40
|
+
expect(dropdownMenu).toBeInTheDocument();
|
|
41
|
+
|
|
42
|
+
// The user should be able to see the list of options
|
|
43
|
+
const addOption = screen.getByText(/add/i);
|
|
44
|
+
expect(addOption).toBeInTheDocument();
|
|
45
|
+
|
|
46
|
+
// The user can interact with any of the options
|
|
47
|
+
await user.click(addOption);
|
|
48
|
+
|
|
49
|
+
// The following expect is failing
|
|
50
|
+
expect(onSelectOption).toBeCalledTimes(1);
|
|
51
|
+
expect(callbackThatShouldNotBeExecuted).toBeCalledTimes(0);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import { VariantProps, cva } from 'class-variance-authority';
|
|
2
3
|
|
|
3
4
|
import { DropdownMenu } from '../dropdown-menu';
|
|
4
5
|
import { Item } from './action-item';
|
|
5
6
|
import { Separator } from './action-item-separator';
|
|
6
7
|
|
|
7
|
-
type
|
|
8
|
+
type ButtonStylesProps = VariantProps<typeof buttonStyles>;
|
|
9
|
+
const buttonStyles = cva('c-action-menu', {
|
|
10
|
+
variants: {
|
|
11
|
+
size: {
|
|
12
|
+
xs: 'c-action-menu-xs',
|
|
13
|
+
sm: 'c-action-menu-sm',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
size: 'sm',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
type ActionMenuProps = ButtonStylesProps & {
|
|
8
22
|
children: ReactNode;
|
|
9
23
|
tabIndex?: number;
|
|
10
24
|
};
|
|
11
25
|
|
|
12
|
-
export function ActionMenu({ children, tabIndex }: ActionMenuProps) {
|
|
26
|
+
export function ActionMenu({ children, tabIndex, size }: ActionMenuProps) {
|
|
13
27
|
return (
|
|
14
28
|
<DropdownMenu.Root content={children} alignContent="center">
|
|
15
|
-
<button
|
|
29
|
+
<button
|
|
30
|
+
aria-label="more options"
|
|
31
|
+
className={buttonStyles({ size })}
|
|
32
|
+
data-testid="action-menu-button"
|
|
33
|
+
tabIndex={tabIndex}
|
|
34
|
+
type="button"
|
|
35
|
+
>
|
|
16
36
|
<span className="sr-only">Open more options</span>
|
|
17
37
|
<span className="c-action-menu-dot"></span>
|
|
18
38
|
<span className="c-action-menu-dot"></span>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
|
|
4
|
+
import { Button } from './index';
|
|
5
|
+
|
|
6
|
+
describe('Button', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
render(<Button>Hey</Button>);
|
|
9
|
+
|
|
10
|
+
expect(screen.getByText(/Hey/i)).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('fires the onClick event', async () => {
|
|
14
|
+
const onClick = vi.fn();
|
|
15
|
+
|
|
16
|
+
render(<Button onClick={onClick}>Hey</Button>);
|
|
17
|
+
|
|
18
|
+
await userEvent.click(screen.getByRole('button'));
|
|
19
|
+
|
|
20
|
+
expect(onClick).toBeCalledTimes(1);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
3
3
|
|
|
4
|
-
type DropdownMenuRootProps = DropdownMenuPrimitive.MenuContentProps & {
|
|
4
|
+
export type DropdownMenuRootProps = DropdownMenuPrimitive.MenuContentProps & {
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
content: ReactNode;
|
|
7
7
|
alignContent?: 'start' | 'center' | 'end';
|
|
@@ -12,7 +12,7 @@ type DropdownMenuRootProps = DropdownMenuPrimitive.MenuContentProps & {
|
|
|
12
12
|
export function DropdownMenuRoot({
|
|
13
13
|
children,
|
|
14
14
|
content,
|
|
15
|
-
alignContent = '
|
|
15
|
+
alignContent = 'center',
|
|
16
16
|
disabled,
|
|
17
17
|
onOpenChange,
|
|
18
18
|
...delegated
|
|
@@ -22,14 +22,16 @@ export function DropdownMenuRoot({
|
|
|
22
22
|
<DropdownMenuPrimitive.Trigger disabled={disabled} asChild>
|
|
23
23
|
{children}
|
|
24
24
|
</DropdownMenuPrimitive.Trigger>
|
|
25
|
-
<DropdownMenuPrimitive.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
<DropdownMenuPrimitive.Portal>
|
|
26
|
+
<DropdownMenuPrimitive.Content
|
|
27
|
+
align={alignContent}
|
|
28
|
+
sideOffset={5}
|
|
29
|
+
className="c-dropdown-menu-content"
|
|
30
|
+
{...delegated}
|
|
31
|
+
>
|
|
32
|
+
{content}
|
|
33
|
+
</DropdownMenuPrimitive.Content>
|
|
34
|
+
</DropdownMenuPrimitive.Portal>
|
|
33
35
|
</DropdownMenuPrimitive.Root>
|
|
34
36
|
);
|
|
35
37
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './popover';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
3
|
+
|
|
4
|
+
import { Icon } from '../iconography';
|
|
5
|
+
|
|
6
|
+
export type PopoverCloseProps = PopoverPrimitive.PopoverCloseProps & {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function PopoverClose(props: PopoverCloseProps) {
|
|
11
|
+
const { asChild, children } = props;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<PopoverPrimitive.Close asChild={asChild} className="c-popover-close">
|
|
15
|
+
{children ?? <Icon.Cancel width={16} height={16} />}
|
|
16
|
+
</PopoverPrimitive.Close>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.c-popover-content {
|
|
2
|
+
@apply rounded bg-elevate text-xs text-gray-700-200 shadow focus-visible:outline-none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.c-popover-close {
|
|
6
|
+
@apply absolute right-1 top-1 flex cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-1;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.c-popover-arrow {
|
|
10
|
+
@apply fill-white;
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Popover } from '.';
|
|
4
|
+
import { Icon } from '../iconography';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Popover> = {
|
|
7
|
+
title: 'Components/Popover',
|
|
8
|
+
component: Popover,
|
|
9
|
+
argTypes: {
|
|
10
|
+
side: {
|
|
11
|
+
options: ['top', 'right', 'bottom', 'left'],
|
|
12
|
+
control: {
|
|
13
|
+
type: 'select',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
align: {
|
|
17
|
+
options: ['start', 'center', 'end'],
|
|
18
|
+
control: {
|
|
19
|
+
type: 'select',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
type Story = StoryObj<typeof Popover>;
|
|
27
|
+
|
|
28
|
+
export const SimpleTemplate: Story = {
|
|
29
|
+
name: 'Simple Template',
|
|
30
|
+
render: args => (
|
|
31
|
+
<div className="flex w-1/2 justify-center pt-14">
|
|
32
|
+
<Popover {...args} content="Content goes here">
|
|
33
|
+
<Icon.Customers width={32} height={32} />
|
|
34
|
+
</Popover>
|
|
35
|
+
</div>
|
|
36
|
+
),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const WithCustomCloseButton: Story = {
|
|
40
|
+
name: 'With custom Close button',
|
|
41
|
+
render: () => (
|
|
42
|
+
<div className="flex w-1/2 justify-center pt-14">
|
|
43
|
+
<Popover content="Content goes here" side="left" closeButton={<button>close</button>}>
|
|
44
|
+
<Icon.Customers width={32} height={32} />
|
|
45
|
+
</Popover>
|
|
46
|
+
</div>
|
|
47
|
+
),
|
|
48
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { cx } from 'class-variance-authority';
|
|
3
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
4
|
+
|
|
5
|
+
import './popover.css';
|
|
6
|
+
import { PopoverClose } from './popover-close';
|
|
7
|
+
|
|
8
|
+
type PopoverProps = Pick<PopoverPrimitive.PopoverProps, 'open' | 'onOpenChange'> &
|
|
9
|
+
Pick<PopoverPrimitive.PortalProps, 'container'> &
|
|
10
|
+
PopoverPrimitive.PopperContentProps & {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
closeButton?: boolean | JSX.Element;
|
|
13
|
+
hasArrow?: boolean;
|
|
14
|
+
content: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function Popover({
|
|
18
|
+
children,
|
|
19
|
+
closeButton,
|
|
20
|
+
content,
|
|
21
|
+
side,
|
|
22
|
+
open,
|
|
23
|
+
onOpenChange,
|
|
24
|
+
className,
|
|
25
|
+
container,
|
|
26
|
+
hasArrow = true,
|
|
27
|
+
...delegatedContent
|
|
28
|
+
}: PopoverProps) {
|
|
29
|
+
return (
|
|
30
|
+
<PopoverPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
31
|
+
<PopoverPrimitive.Trigger asChild>{children}</PopoverPrimitive.Trigger>
|
|
32
|
+
<PopoverPrimitive.Portal container={container}>
|
|
33
|
+
<PopoverPrimitive.Content {...delegatedContent} side={side} className={cx('c-popover-content', className)}>
|
|
34
|
+
{!closeButton ? null : (
|
|
35
|
+
<PopoverClose asChild={typeof closeButton !== 'boolean'}>
|
|
36
|
+
{typeof closeButton !== 'boolean' ? closeButton : null}
|
|
37
|
+
</PopoverClose>
|
|
38
|
+
)}
|
|
39
|
+
{hasArrow && <PopoverPrimitive.Arrow className="c-popover-arrow" offset={5} />}
|
|
40
|
+
{content}
|
|
41
|
+
</PopoverPrimitive.Content>
|
|
42
|
+
</PopoverPrimitive.Portal>
|
|
43
|
+
</PopoverPrimitive.Root>
|
|
44
|
+
);
|
|
45
|
+
}
|