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 ; case 'webframe': return ; + case 'input': + return ; default: 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 ); }