From 8beb5d6bcf803b02e2f46c79ed46fcd32ce628fc Mon Sep 17 00:00:00 2001
From: "Nolann B." <100787331+nolannbiron@users.noreply.github.com>
Date: Fri, 28 Feb 2025 18:50:20 +0100
Subject: [PATCH] Add input elements to ContentKit (#2882)
---
.changeset/violet-penguins-drum.md | 6 ++
bun.lock | 13 ++--
.../DocumentView/Integration/contentkit.css | 39 ++++++++--
packages/react-contentkit/package.json | 3 +-
packages/react-contentkit/src/Element.tsx | 3 +
.../react-contentkit/src/ElementButton.tsx | 23 +++---
.../react-contentkit/src/ElementInput.tsx | 74 +++++++++++++++++++
.../react-contentkit/src/ElementTextInput.tsx | 1 +
8 files changed, 139 insertions(+), 23 deletions(-)
create mode 100644 .changeset/violet-penguins-drum.md
create mode 100644 packages/react-contentkit/src/ElementInput.tsx
diff --git a/.changeset/violet-penguins-drum.md b/.changeset/violet-penguins-drum.md
new file mode 100644
index 000000000..0fe5e87d8
--- /dev/null
+++ b/.changeset/violet-penguins-drum.md
@@ -0,0 +1,6 @@
+---
+'@gitbook/react-contentkit': patch
+'gitbook': patch
+---
+
+Add input elements to ContentKit
diff --git a/bun.lock b/bun.lock
index fb4a03bc9..6db506b05 100644
--- a/bun.lock
+++ b/bun.lock
@@ -38,7 +38,7 @@
},
"packages/gitbook": {
"name": "gitbook",
- "version": "0.6.3",
+ "version": "0.6.4",
"dependencies": {
"@gitbook/api": "0.96.1",
"@gitbook/cache-do": "workspace:*",
@@ -118,7 +118,7 @@
},
"packages/gitbook-v2": {
"name": "gitbook-v2",
- "version": "0.1.0",
+ "version": "0.1.1",
"dependencies": {
"@gitbook/api": "0.96.1",
"@sindresorhus/fnv1a": "^3.1.0",
@@ -138,7 +138,7 @@
"name": "@gitbook/icons",
"version": "0.1.0",
"bin": {
- "gitbook-icons": "./bin/gitbook-icons.js",
+ "gitbook-icons": "./bin/gitbook-icons.js"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.6.0",
@@ -156,7 +156,7 @@
},
"packages/openapi-parser": {
"name": "@gitbook/openapi-parser",
- "version": "2.0.0",
+ "version": "2.0.1",
"dependencies": {
"@scalar/openapi-parser": "^0.10.4",
"@scalar/openapi-types": "^0.1.6",
@@ -181,6 +181,7 @@
"version": "0.6.0",
"dependencies": {
"@gitbook/api": "0.96.1",
+ "@gitbook/icons": "workspace:*",
"assert-never": "^1.2.1",
"classnames": "^2.5.1",
},
@@ -195,7 +196,7 @@
"name": "@gitbook/react-math",
"version": "0.6.0",
"bin": {
- "gitbook-math": "./bin/gitbook-math.js",
+ "gitbook-math": "./bin/gitbook-math.js"
},
"dependencies": {
"object-hash": "^3.0.0",
@@ -210,7 +211,7 @@
},
"packages/react-openapi": {
"name": "@gitbook/react-openapi",
- "version": "1.0.3",
+ "version": "1.0.4",
"dependencies": {
"@gitbook/openapi-parser": "workspace:*",
"@scalar/api-client-react": "1.0.87",
diff --git a/packages/gitbook/src/components/DocumentView/Integration/contentkit.css b/packages/gitbook/src/components/DocumentView/Integration/contentkit.css
index 2b7e6ac52..e28319b7e 100644
--- a/packages/gitbook/src/components/DocumentView/Integration/contentkit.css
+++ b/packages/gitbook/src/components/DocumentView/Integration/contentkit.css
@@ -3,8 +3,13 @@
@apply flex gap-4;
}
+/** Add margin bottom to all stacks that are not the last child and have a form */
+.contentkit-stack:not(:last-child):has(.contentkit-form) {
+ @apply mb-4;
+}
+
.contentkit-hstack {
- @apply flex-row gap-4 items-center;
+ @apply flex-row gap-3 items-center;
}
.contentkit-hstack.contentkit-stack-align-center {
@apply justify-center;
@@ -88,17 +93,23 @@
/** Buttons */
.contentkit-button {
- @apply flex gap-2 items-center justify-center px-2 py-1 rounded
- border border-tint hover:border-tint-hover
- text-tint hover:text-tint-strong;
+ @apply text-sm px-3 h-8 text-center inline-block py-1.5 rounded-md straight-corners:rounded-none place-self-start ring-1 ring-tint hover:ring-tint-hover shadow-sm shadow-tint dark:shadow-tint-1 hover:shadow-md active:shadow-none contrast-more:ring-tint-12 contrast-more:hover:ring-2 contrast-more:hover:ring-tint-12 hover:scale-105 active:scale-100 transition-all grow-0 shrink-0 truncate w-full;
+}
+
+.contentkit-button-style-primary {
+ @apply bg-primary-solid text-contrast-primary-solid hover:bg-primary-solid-hover hover:text-contrast-primary-solid-hover ring-0 contrast-more:ring-1;
+}
+
+.contentkit-button-style-secondary {
+ @apply bg-tint text-tint hover:bg-tint-hover hover:text-primary contrast-more:bg-tint-subtle;
}
.contentkit-button .contentkit-icon {
@apply w-4 h-4;
}
-.contentkit-button .contentkit-button-label {
- @apply text-sm font-medium text-tint-strong;
+.contentkit-button-loading {
+ @apply size-5 flex mx-auto animate-spin;
}
/** Modals */
@@ -143,7 +154,21 @@
/** Text input */
.contentkit-textinput {
- @apply w-full px-2 py-1 rounded border border-tint text-sm text-tint;
+ @apply w-full rounded border border-tint text-tint-strong placeholder:text-tint flex resize-none flex-1 px-2 py-1.5 text-sm bg-transparent whitespace-pre-line;
+ @apply focus:outline-primary focus:border-primary;
+}
+
+/** Form */
+.contentkit-form {
+ @apply flex flex-col gap-1;
+}
+
+.contentkit-form:not(:first-of-type) {
+ @apply mt-4;
+}
+
+.contentkit-label {
+ @apply text-sm font-medium text-tint-strong;
}
/** Dividers */
diff --git a/packages/react-contentkit/package.json b/packages/react-contentkit/package.json
index 0b988cc92..ef79e287e 100644
--- a/packages/react-contentkit/package.json
+++ b/packages/react-contentkit/package.json
@@ -11,7 +11,8 @@
"dependencies": {
"classnames": "^2.5.1",
"@gitbook/api": "0.96.1",
- "assert-never": "^1.2.1"
+ "assert-never": "^1.2.1",
+ "@gitbook/icons": "workspace:*"
},
"peerDependencies": {
"react": "*"
diff --git a/packages/react-contentkit/src/Element.tsx b/packages/react-contentkit/src/Element.tsx
index ab54f9c28..02104f3d0 100644
--- a/packages/react-contentkit/src/Element.tsx
+++ b/packages/react-contentkit/src/Element.tsx
@@ -13,6 +13,7 @@ import { ElementCodeBlock } from './ElementCodeBlock';
import { ElementDivider } from './ElementDivider';
import { ElementIcon } from './ElementIcon';
import { ElementImage } from './ElementImage';
+import { ElementInput } from './ElementInput';
import { ElementMarkdown } from './ElementMarkdown';
import { ElementModal } from './ElementModal';
import { ElementStack } from './ElementStack';
@@ -152,6 +153,8 @@ export function Element(props: {
return
{
if (element.disabled || loading) {
@@ -43,11 +42,17 @@ export function ElementButton(
});
}}
>
- {icon}
- {element.label ? (
- {element.label}
- ) : null}
- {trailingIcon}
+ {loading ? (
+
+ ) : (
+ <>
+ {icon}
+ {element.label ? (
+ {element.label}
+ ) : null}
+ {trailingIcon}
+ >
+ )}
);
}
diff --git a/packages/react-contentkit/src/ElementInput.tsx b/packages/react-contentkit/src/ElementInput.tsx
new file mode 100644
index 000000000..149ba520a
--- /dev/null
+++ b/packages/react-contentkit/src/ElementInput.tsx
@@ -0,0 +1,74 @@
+import type {
+ ContentKitButton,
+ ContentKitCheckbox,
+ ContentKitCodeBlock,
+ ContentKitInput,
+ ContentKitRadio,
+ ContentKitSelect,
+ ContentKitSwitch,
+ ContentKitTextInput,
+} from '@gitbook/api';
+import classNames from 'classnames';
+import { ElementButton } from './ElementButton';
+import { ElementCodeBlock } from './ElementCodeBlock';
+import { ElementIcon } from './ElementIcon';
+import { ElementTextInput } from './ElementTextInput';
+import type { ContentKitServerContext } from './types';
+
+export function ElementInput(props: {
+ element: ContentKitInput;
+ context: ContentKitServerContext;
+ state: object;
+}) {
+ const { element, context, state } = props;
+ const { label, element: childElement } = element;
+
+ return (
+
+ {label ? : null}
+ {getInputElement({ element: childElement, context, state })}
+
+ );
+}
+
+function getInputElement(props: {
+ element:
+ | ContentKitTextInput
+ | ContentKitSelect
+ | ContentKitSwitch
+ | ContentKitRadio
+ | ContentKitCheckbox
+ | ContentKitButton
+ | ContentKitCodeBlock;
+ context: ContentKitServerContext;
+ state: object;
+}) {
+ const { element, context, state } = props;
+
+ //!!TODO add support for:
+ // - select
+ // - switch
+ // - radio
+ // - checkbox
+
+ switch (element.type) {
+ case 'textinput':
+ return ;
+ case 'button':
+ return (
+ : null
+ }
+ trailingIcon={
+ element.trailingIcon ? (
+
+ ) : null
+ }
+ />
+ );
+ case 'codeblock':
+ return ;
+ }
+}
diff --git a/packages/react-contentkit/src/ElementTextInput.tsx b/packages/react-contentkit/src/ElementTextInput.tsx
index 026149aab..e22e12047 100644
--- a/packages/react-contentkit/src/ElementTextInput.tsx
+++ b/packages/react-contentkit/src/ElementTextInput.tsx
@@ -29,6 +29,7 @@ export function ElementTextInput(props: ContentKitClientElementProps
);
}