@blockle/blocks 0.7.2 → 0.8.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.mjs CHANGED
@@ -6,14 +6,16 @@ import { makeTheme } from "./styles/lib/theme/makeTheme.mjs";
6
6
  import { vars } from "./styles/lib/theme/vars.css.mjs";
7
7
  import { atoms } from "./styles/lib/css/atoms/sprinkles.css.mjs";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { createContext, forwardRef, useContext, useEffect, useRef, useLayoutEffect, useState, useCallback, useId } from "react";
9
+ import { createContext, forwardRef, Children, isValidElement, cloneElement, useContext, useEffect, useRef, useLayoutEffect, useState, useCallback, useId } from "react";
10
10
  import { buttonReset } from "./styles/components/Button/Button.css.mjs";
11
11
  import { container, input, icon } from "./styles/components/Checkbox/checkbox.css.mjs";
12
12
  import { backdropLeaveAnimation, backdropLeave, backdrop, dialogLeave, dialog } from "./styles/components/Dialog/dialog.css.mjs";
13
13
  import { createPortal } from "react-dom";
14
14
  import { divider } from "./styles/components/Divider/divider.css.mjs";
15
+ import { heading } from "./styles/components/Heading/heading.css.mjs";
15
16
  import { input as input$1 } from "./styles/components/Input/input.css.mjs";
16
17
  import { container as container$1, input as input$2, icon as icon$1 } from "./styles/components/Radio/radio.css.mjs";
18
+ import { text } from "./styles/components/Text/text.css.mjs";
17
19
  const classnames = (...args) => {
18
20
  const className = args.filter((arg) => arg && typeof arg === "string").join(" ");
19
21
  return className || void 0;
@@ -34,19 +36,130 @@ const BlocksProvider = ({
34
36
  }
35
37
  ) });
36
38
  };
37
- const defaultElement$1 = "div";
38
- const Box = forwardRef(function Box2({ className, as, ...restProps }, ref) {
39
- const Component = as || defaultElement$1;
39
+ function getAtomsAndProps(props) {
40
40
  const atomProps = {};
41
41
  const otherProps = {};
42
- for (const [name, value] of Object.entries(restProps)) {
42
+ for (const [name, value] of Object.entries(props)) {
43
43
  if (atoms.properties.has(name)) {
44
44
  atomProps[name] = value;
45
45
  } else {
46
46
  otherProps[name] = value;
47
47
  }
48
48
  }
49
- return /* @__PURE__ */ jsx(Component, { ref, className: classnames(className, atoms(atomProps)), ...otherProps });
49
+ return [atomProps, otherProps];
50
+ }
51
+ function setRef(ref, value) {
52
+ if (typeof ref === "function") {
53
+ ref(value);
54
+ } else if (ref !== null && ref !== void 0) {
55
+ ref.current = value;
56
+ }
57
+ }
58
+ function composeRefs(...refs) {
59
+ return (node) => {
60
+ for (const ref of refs) {
61
+ setRef(ref, node);
62
+ }
63
+ };
64
+ }
65
+ function mergeProps(slotProps, childProps) {
66
+ const overrideProps = {};
67
+ for (const propName in childProps) {
68
+ const slotPropValue = slotProps[propName];
69
+ const childPropValue = childProps[propName];
70
+ if (childPropValue === void 0) {
71
+ continue;
72
+ }
73
+ if (slotPropValue === void 0) {
74
+ overrideProps[propName] = childPropValue;
75
+ continue;
76
+ }
77
+ if (typeof slotPropValue === "function" && typeof childPropValue === "function") {
78
+ overrideProps[propName] = (...args) => {
79
+ childPropValue(...args);
80
+ slotPropValue(...args);
81
+ };
82
+ } else if (propName === "style") {
83
+ overrideProps[propName] = { ...slotPropValue, ...childPropValue };
84
+ } else if (propName === "className") {
85
+ overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
86
+ } else {
87
+ overrideProps[propName] = childPropValue;
88
+ }
89
+ }
90
+ return { ...slotProps, ...overrideProps };
91
+ }
92
+ function createSlottable(defaultElement) {
93
+ function Slottable2(props, ref) {
94
+ const { asChild, children, ...slotProps } = props;
95
+ const Component = defaultElement;
96
+ if (!asChild) {
97
+ return /* @__PURE__ */ jsx(Component, { ref, ...slotProps, children });
98
+ }
99
+ const childrenArray = Children.toArray(children);
100
+ const slot = childrenArray.find((child) => {
101
+ if (!isValidElement(child)) {
102
+ return false;
103
+ }
104
+ return child.type === Slot;
105
+ });
106
+ if (!slot) {
107
+ const Slot2 = childrenArray[0];
108
+ if (!isValidElement(childrenArray[0])) {
109
+ if (process.env.NODE_ENV === "development") {
110
+ console.warn("Slottable: First child is not a valid React element");
111
+ }
112
+ return null;
113
+ }
114
+ if (!isValidElement(Slot2)) {
115
+ return null;
116
+ }
117
+ return cloneElement(
118
+ Slot2,
119
+ {
120
+ ...mergeProps(slotProps, Slot2.props),
121
+ ref: composeRefs(ref, Slot2.ref)
122
+ },
123
+ Slot2.props.children
124
+ );
125
+ }
126
+ if (!isValidElement(slot) || !isValidElement(slot.props.children)) {
127
+ return null;
128
+ }
129
+ const newChildren = childrenArray.map((child) => {
130
+ if (!isValidElement(child)) {
131
+ return child;
132
+ }
133
+ if (child.type === Slot) {
134
+ return slot.props.children.props.children;
135
+ }
136
+ return child;
137
+ });
138
+ return cloneElement(
139
+ slot.props.children,
140
+ {
141
+ ...mergeProps(slotProps, slot.props),
142
+ ref: composeRefs(ref, slot.props.children.ref)
143
+ },
144
+ newChildren
145
+ );
146
+ }
147
+ return forwardRef(Slottable2);
148
+ }
149
+ const Slot = ({ children }) => children;
150
+ const Slottable$2 = createSlottable("div");
151
+ const Box = forwardRef(function Box2({ asChild, className, children, ...restProps }, ref) {
152
+ const [atomsProps, otherProps] = getAtomsAndProps(restProps);
153
+ return /* @__PURE__ */ jsx(
154
+ Slottable$2,
155
+ {
156
+ ref,
157
+ asChild,
158
+ className: classnames(className, atoms(atomsProps)),
159
+ ...otherProps,
160
+ children
161
+ }
162
+ );
50
163
  });
51
164
  const useTheme = () => {
52
165
  const theme = useContext(BlocksProviderContext);
@@ -87,7 +200,7 @@ function useComponentStyles(name, props, useDefaultVariants = true) {
87
200
  const componentVariants = component.variants;
88
201
  for (const key of keys) {
89
202
  const value = variantsWithDefaults[key];
90
- if (value === void 0) {
203
+ if (value === void 0 || componentVariants[key] === void 0) {
91
204
  continue;
92
205
  }
93
206
  if (typeof value === "boolean") {
@@ -131,18 +244,18 @@ const Spinner = ({ className, size, color, ...restProps }) => {
131
244
  const spinnerClassName = useComponentStyles("spinner", { base: true, variants: { size, color } });
132
245
  return /* @__PURE__ */ jsx(Box, { color, className: classnames(spinnerClassName, className), ...restProps });
133
246
  };
247
+ const Slottable$1 = createSlottable("button");
134
248
  const Button = forwardRef(function Button2({
135
249
  children,
136
250
  className,
137
- type = "button",
138
251
  variant,
139
252
  intent,
140
253
  size,
141
- width,
142
254
  startSlot,
143
255
  endSlot,
144
256
  loading,
145
257
  disabled,
258
+ asChild,
146
259
  ...restProps
147
260
  }, ref) {
148
261
  const buttonClassName = useComponentStyles("button", {
@@ -155,21 +268,20 @@ const Button = forwardRef(function Button2({
155
268
  loading
156
269
  }
157
270
  });
271
+ const [atomsProps, otherProps] = getAtomsAndProps(restProps);
158
272
  return /* @__PURE__ */ jsxs(
159
- Box,
273
+ Slottable$1,
160
274
  {
161
275
  ref,
162
- as: "button",
163
- className: classnames(buttonReset, buttonClassName, className),
164
- width,
165
- type,
276
+ asChild,
166
277
  disabled: disabled || loading,
167
- ...restProps,
278
+ className: classnames(buttonReset, buttonClassName, atoms(atomsProps), className),
279
+ ...otherProps,
168
280
  children: [
169
- startSlot && /* @__PURE__ */ jsx(Box, { paddingRight: "medium", children: startSlot }),
170
- loading && /* @__PURE__ */ jsx(Spinner, { size, marginRight: "medium" }),
171
- children,
172
- endSlot && /* @__PURE__ */ jsx(Box, { paddingLeft: "medium", children: endSlot })
281
+ startSlot && /* @__PURE__ */ jsx("div", { children: startSlot }),
282
+ loading && /* @__PURE__ */ jsx(Spinner, { size }),
283
+ /* @__PURE__ */ jsx(Slot, { children }),
284
+ endSlot && /* @__PURE__ */ jsx("div", { children: endSlot })
173
285
  ]
174
286
  }
175
287
  );
@@ -376,10 +488,9 @@ const Dialog = ({
376
488
  onClick: onBackdropClick,
377
489
  onAnimationEnd,
378
490
  children: /* @__PURE__ */ jsx(
379
- Box,
491
+ "dialog",
380
492
  {
381
493
  ref: dialogRef,
382
- as: "dialog",
383
494
  "aria-modal": "true",
384
495
  open: true,
385
496
  className: classnames(
@@ -419,20 +530,18 @@ const Heading = ({
419
530
  fontFamily,
420
531
  ...restProps
421
532
  }) => {
422
- const as = `h${level}`;
533
+ const Tag = `h${level}`;
423
534
  return /* @__PURE__ */ jsx(
424
535
  Box,
425
536
  {
426
- as,
427
- className,
537
+ asChild: true,
538
+ className: classnames(heading, className),
428
539
  fontFamily,
429
540
  fontWeight,
430
541
  fontSize,
431
542
  textAlign: align,
432
- padding: "none",
433
- margin: "none",
434
543
  ...restProps,
435
- children
544
+ children: /* @__PURE__ */ jsx(Tag, { children })
436
545
  }
437
546
  );
438
547
  };
@@ -452,7 +561,7 @@ const alignItemsMap = {
452
561
  const Inline = ({
453
562
  alignX,
454
563
  alignY,
455
- as = "div",
564
+ tag: Tag = "div",
456
565
  children,
457
566
  display = "flex",
458
567
  gap,
@@ -461,7 +570,7 @@ const Inline = ({
461
570
  return /* @__PURE__ */ jsx(
462
571
  Box,
463
572
  {
464
- as,
573
+ asChild: true,
465
574
  display,
466
575
  gap,
467
576
  flexDirection: "row",
@@ -469,7 +578,7 @@ const Inline = ({
469
578
  alignItems: alignY ? alignItemsMap[alignY] : void 0,
470
579
  flexWrap: "wrap",
471
580
  ...props,
472
- children
581
+ children: /* @__PURE__ */ jsx(Tag, { children })
473
582
  }
474
583
  );
475
584
  };
@@ -479,32 +588,37 @@ const Input = forwardRef(function Input2({ className, name, type = "text", start
479
588
  const inputClassName = useComponentStyles("input", { input: true });
480
589
  return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", className: classnames(containerClassName, className), children: [
481
590
  startSlot,
482
- /* @__PURE__ */ jsx(
483
- Box,
591
+ /* @__PURE__ */ jsx(Box, { asChild: true, width: "full", overflow: "hidden", children: /* @__PURE__ */ jsx(
592
+ "input",
484
593
  {
485
- as: "input",
486
594
  id,
487
595
  ref,
488
596
  name,
489
597
  type,
490
598
  placeholder: placeholder || label,
491
- width: "full",
492
- overflow: "hidden",
493
599
  className: classnames(input$1, inputClassName),
494
600
  ...restProps
495
601
  }
496
- ),
602
+ ) }),
497
603
  endSlot
498
604
  ] }) });
499
605
  });
500
- const defaultElement = "a";
501
- const Link = forwardRef(function Link2({ as, className, variant, underline, ...restProps }, ref) {
502
- const Component = as || defaultElement;
606
+ const Slottable = createSlottable("a");
607
+ const Link = forwardRef(function Link2({ asChild, className, children, variant, underline, ...restProps }, ref) {
503
608
  const linkClassName = useComponentStyles("link", {
504
609
  base: true,
505
610
  variants: { variant, underline }
506
611
  });
507
- return /* @__PURE__ */ jsx(Box, { ref, as: Component, className: classnames(className, linkClassName), ...restProps });
612
+ return /* @__PURE__ */ jsx(
613
+ Slottable,
614
+ {
615
+ asChild,
616
+ ref,
617
+ className: classnames(className, linkClassName),
618
+ ...restProps,
619
+ children
620
+ }
621
+ );
508
622
  });
509
623
  const Radio = forwardRef(function Checkbox3({ name, label, className, ...restProps }, ref) {
510
624
  const containerClassName = useComponentStyles("radio", { base: true }, false);
@@ -523,55 +637,57 @@ const Radio = forwardRef(function Checkbox3({ name, label, className, ...restPro
523
637
  ] });
524
638
  });
525
639
  const Stack = ({
526
- as = "div",
640
+ tag: Tag = "div",
527
641
  display = "flex",
528
642
  children,
529
643
  gap,
530
644
  alignX,
531
645
  ...restProps
532
646
  }) => {
533
- if (process.env.NODE_ENV === "development" && restProps.start !== void 0 && as !== "ol") {
534
- console.warn('Stack: start prop is only valid when as="ol"');
647
+ if (process.env.NODE_ENV === "development" && restProps.start !== void 0 && Tag !== "ol") {
648
+ console.warn('Stack: start prop is only valid when tag="ol"');
535
649
  }
536
650
  return /* @__PURE__ */ jsx(
537
651
  Box,
538
652
  {
539
- as,
653
+ asChild: true,
540
654
  display,
541
655
  gap,
542
656
  flexDirection: "column",
543
657
  alignItems: alignX ? alignItemsMap[alignX] : void 0,
544
658
  ...restProps,
545
- children
659
+ children: /* @__PURE__ */ jsx(Tag, { children })
546
660
  }
547
661
  );
548
662
  };
549
- const Text = ({
550
- as = "span",
663
+ const Text = forwardRef(function Text2({
664
+ tag: Tag = "span",
665
+ asChild,
551
666
  children,
552
667
  color,
553
668
  fontSize,
554
669
  fontWeight,
555
670
  fontFamily,
556
671
  textAlign,
672
+ className,
557
673
  ...restProps
558
- }) => {
674
+ }, ref) {
559
675
  return /* @__PURE__ */ jsx(
560
676
  Box,
561
677
  {
562
- as,
678
+ ref,
679
+ asChild: true,
563
680
  color,
564
681
  fontSize,
565
682
  fontWeight,
566
683
  fontFamily,
567
684
  textAlign,
568
- padding: "none",
569
- margin: "none",
685
+ className: classnames(text, className),
570
686
  ...restProps,
571
- children
687
+ children: asChild ? children : /* @__PURE__ */ jsx(Tag, { children })
572
688
  }
573
689
  );
574
- };
690
+ });
575
691
  export {
576
692
  BlocksProvider,
577
693
  Box,
@@ -586,12 +702,14 @@ export {
586
702
  Link,
587
703
  Portal,
588
704
  Radio,
705
+ Slot,
589
706
  Spinner,
590
707
  Stack,
591
708
  Text,
592
709
  atoms,
593
710
  breakpointQuery,
594
711
  classnames,
712
+ createSlottable,
595
713
  makeComponentTheme,
596
714
  makeTheme,
597
715
  useComponentStyleDefaultProps,