@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 +42 -0
- package/dist/Slot/Slot.cjs +6 -0
- package/dist/Slot/Slot.d.ts +5 -0
- package/dist/Slot/Slot.js +6 -0
- package/dist/createSlottable.cjs +58 -0
- package/dist/createSlottable.d.ts +32 -0
- package/dist/createSlottable.js +58 -0
- package/dist/index.cjs +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/package.json +44 -0
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,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;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
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
|
+
}
|