@blockle/blocks-react-slot 1.0.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/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @blockle/blocks-slot
2
+
3
+ A simple slot component for React.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @blockle/blocks-slot
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { createSlottable, Slot } from '@blockle/blocks-slot';
15
+
16
+ const Template = createSlottable('button'); // Provide a default tag name
17
+
18
+ export const Button = ({asChild}) => {
19
+ return (
20
+ // Template setup
21
+ <Template className="btn" onClick={() => console.log('clicked')}>
22
+ [ICON]
23
+ <Slot>{asChild}</Slot>
24
+ </Template>
25
+ );
26
+ };
27
+ ```
28
+
29
+ ```tsx
30
+ import { Button } from './Button';
31
+
32
+ export const App = () => {
33
+ return (
34
+ <>
35
+ <Button>Button</Button> {/* -> <button class="btn">[ICON] Tag button</button> */}
36
+ <Button asChild>
37
+ <a href="/">Anchor</a>
38
+ </Button> {/* -> <a class="btn">[ICON] Tag a</a> */}
39
+ </>
40
+ );
41
+ };
42
+ ```
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const Slot = ({ children }) => {
4
+ return children;
5
+ };
6
+ exports.Slot = Slot;
@@ -0,0 +1,5 @@
1
+ type SlotProps = {
2
+ children: React.ReactNode;
3
+ };
4
+ export declare const Slot: React.FC<SlotProps>;
5
+ export {};
@@ -0,0 +1,6 @@
1
+ const Slot = ({ children }) => {
2
+ return children;
3
+ };
4
+ export {
5
+ Slot
6
+ };
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const blocksCore = require("@blockle/blocks-core");
5
+ const react = require("react");
6
+ const Slot = require("./Slot/Slot.cjs");
7
+ function createSlottable(defaultElement) {
8
+ const Tag = defaultElement;
9
+ const Template = ({
10
+ asChild,
11
+ children,
12
+ ref,
13
+ ...rootProps
14
+ }) => {
15
+ if (!asChild) {
16
+ const tagProps = { ref, ...rootProps };
17
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { ...tagProps, children });
18
+ }
19
+ const childrenArray = react.Children.toArray(children);
20
+ const slotIndex = childrenArray.findIndex((child) => {
21
+ if (!react.isValidElement(child)) {
22
+ return false;
23
+ }
24
+ return child.type === Slot.Slot;
25
+ });
26
+ const slot = childrenArray[slotIndex];
27
+ if (!slot) {
28
+ return null;
29
+ }
30
+ if (!isValidElementWithChildren(slot)) {
31
+ return null;
32
+ }
33
+ if (!react.isValidElement(slot.props.children)) {
34
+ return null;
35
+ }
36
+ if (!isValidElementWithChildren(slot.props.children)) {
37
+ return null;
38
+ }
39
+ const nextChildren = [...childrenArray];
40
+ if (nextChildren.length === 1 && !slot.props.children.props.children) {
41
+ return react.cloneElement(
42
+ slot.props.children,
43
+ blocksCore.mergeProps(rootProps, slot.props.children.props)
44
+ );
45
+ }
46
+ nextChildren[slotIndex] = slot.props.children.props.children;
47
+ return react.cloneElement(
48
+ slot.props.children,
49
+ blocksCore.mergeProps(rootProps, slot.props.children.props),
50
+ nextChildren
51
+ );
52
+ };
53
+ return [Template, Slot.Slot];
54
+ }
55
+ function isValidElementWithChildren(child) {
56
+ return react.isValidElement(child) && !!child.props;
57
+ }
58
+ exports.createSlottable = createSlottable;
@@ -0,0 +1,32 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ import { default as React } from 'react';
3
+ import { Slot } from './Slot/Slot';
4
+ type TemplateProps = {
5
+ asChild?: boolean;
6
+ children?: React.ReactNode;
7
+ ref?: React.Ref<Element>;
8
+ };
9
+ /**
10
+ * Create a Template component that can render as a child of another component with asChild prop.
11
+ *
12
+ * Example
13
+ * // Create a Template and Slot components with div as default element
14
+ * const { Template, Slot } = createAsChildContainer('div');
15
+ *
16
+ * const MyComponent = ({ children, asChild, ...restProps }) => {
17
+ * return (
18
+ * <Template asChild={asChild} {...restProps}>
19
+ * <Slot>{childen}</Slot> // Slot is required, will be replaced with children
20
+ * </Template>
21
+ * );
22
+ * }
23
+ *
24
+ * <MyComponent className="test">Not a link</MyComponent> // Renders as <div class="test">Not a link</div>
25
+ * <MyComponent className="test"><a href="#">Link</a></MyComponent> // Renders as <div class="test"><a href="#">Link</a></div>
26
+ * <MyComponent className="test" asChild><a href="#">Link</a></MyComponent> // Renders as <a href="#" class="test">Link</a>
27
+ */
28
+ export declare function createSlottable<T extends keyof HTMLElementTagNameMap>(defaultElement: T): [
29
+ Template: React.FC<TemplateProps & HTMLElementProps<HTMLElementTagNameMap[T]>>,
30
+ Slot: typeof Slot
31
+ ];
32
+ export {};
@@ -0,0 +1,58 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { mergeProps } from "@blockle/blocks-core";
3
+ import { Children, isValidElement, cloneElement } from "react";
4
+ import { Slot } from "./Slot/Slot.js";
5
+ function createSlottable(defaultElement) {
6
+ const Tag = defaultElement;
7
+ const Template = ({
8
+ asChild,
9
+ children,
10
+ ref,
11
+ ...rootProps
12
+ }) => {
13
+ if (!asChild) {
14
+ const tagProps = { ref, ...rootProps };
15
+ return /* @__PURE__ */ jsx(Tag, { ...tagProps, children });
16
+ }
17
+ const childrenArray = Children.toArray(children);
18
+ const slotIndex = childrenArray.findIndex((child) => {
19
+ if (!isValidElement(child)) {
20
+ return false;
21
+ }
22
+ return child.type === Slot;
23
+ });
24
+ const slot = childrenArray[slotIndex];
25
+ if (!slot) {
26
+ return null;
27
+ }
28
+ if (!isValidElementWithChildren(slot)) {
29
+ return null;
30
+ }
31
+ if (!isValidElement(slot.props.children)) {
32
+ return null;
33
+ }
34
+ if (!isValidElementWithChildren(slot.props.children)) {
35
+ return null;
36
+ }
37
+ const nextChildren = [...childrenArray];
38
+ if (nextChildren.length === 1 && !slot.props.children.props.children) {
39
+ return cloneElement(
40
+ slot.props.children,
41
+ mergeProps(rootProps, slot.props.children.props)
42
+ );
43
+ }
44
+ nextChildren[slotIndex] = slot.props.children.props.children;
45
+ return cloneElement(
46
+ slot.props.children,
47
+ mergeProps(rootProps, slot.props.children.props),
48
+ nextChildren
49
+ );
50
+ };
51
+ return [Template, Slot];
52
+ }
53
+ function isValidElementWithChildren(child) {
54
+ return isValidElement(child) && !!child.props;
55
+ }
56
+ export {
57
+ createSlottable
58
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const createSlottable = require("./createSlottable.cjs");
4
+ const Slot = require("./Slot/Slot.cjs");
5
+ exports.createSlottable = createSlottable.createSlottable;
6
+ exports.Slot = Slot.Slot;
@@ -0,0 +1,2 @@
1
+ export { createSlottable } from './createSlottable';
2
+ export { Slot } from './Slot/Slot';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { createSlottable } from "./createSlottable.js";
2
+ import { Slot } from "./Slot/Slot.js";
3
+ export {
4
+ Slot,
5
+ createSlottable
6
+ };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@blockle/blocks-react-slot",
3
+ "version": "1.0.0",
4
+ "description": "Slot",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": {
9
+ "import": "./dist/index.d.mts",
10
+ "require": "./dist/index.d.ts"
11
+ },
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "main": "./dist/index.cjs",
21
+ "module": "./dist/index.mjs",
22
+ "types": "./dist/index.d.ts",
23
+ "scripts": {
24
+ "build": "vite build",
25
+ "test": "vitest ",
26
+ "lint": "biome format ./src",
27
+ "format": "biome format --write ./src",
28
+ "ts": "tsc --noemit --project ./tsconfig.json"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+ssh://git@github.com/Blockle/blocks.git"
33
+ },
34
+ "author": "Niek Saarberg <n.saarberg@gmail.com>",
35
+ "license": "MIT",
36
+ "bugs": {
37
+ "url": "https://github.com/Blockle/blocks/issues"
38
+ },
39
+ "homepage": "https://github.com/Blockle/blocks#readme",
40
+ "peerDependencies": {
41
+ "react": ">=19.0.0",
42
+ "@blockle/blocks-core": "^0.21.0"
43
+ }
44
+ }