diff --git a/dev/bun.lock b/dev/bun.lock
index cf67529..2a3d5d9 100644
--- a/dev/bun.lock
+++ b/dev/bun.lock
@@ -5,7 +5,7 @@
"": {
"name": "@moduletrace/twui-dev",
"dependencies": {
- "@moduletrace/bunext": "^1.3.4",
+ "@moduletrace/bunext": "^1.3.5",
"lucide-react": "^1.59.0",
},
"devDependencies": {
@@ -78,7 +78,7 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "@moduletrace/bunext": ["@moduletrace/bunext@1.3.4", "https://git.tben.me/api/packages/Moduletrace/npm/%40moduletrace%2Fbunext/-/1.3.4/bunext-1.3.4.tgz", { "dependencies": { "@tailwindcss/postcss": "^4.3.3", "@types/bun": "1.3.14", "@types/node": "^24.10.0", "@types/react": "^19.3.0", "@types/react-dom": "^19.3.0", "bun-plugin-tailwind": "^0.1.2", "chalk": "^5.6.2", "chokidar": "^5.0.0", "commander": "^14.0.2", "esbuild": "^0.28.2", "lightningcss-wasm": "^1.32.0", "lodash": "^4.18.1", "ora": "^9.0.0", "postcss": "^8.5.30", "react": "^19.3.0", "react-dom": "^19.3.0", "tailwindcss": "^4.3.3", "typescript": "^5.0.0", "uuid": "^14.0.2" }, "bin": { "bunext": "dist/commands/index.js" } }, "sha512-+WERTs024+7c2RiynwxngPhShPOexnA2qriVe38JTDAEzl2bqHq97WBecJhD6z7R+VTMibfx+ODikHBXcWEj8Q=="],
+ "@moduletrace/bunext": ["@moduletrace/bunext@1.3.5", "https://git.tben.me/api/packages/Moduletrace/npm/%40moduletrace%2Fbunext/-/1.3.5/bunext-1.3.5.tgz", { "dependencies": { "@tailwindcss/postcss": "^4.3.3", "@types/bun": "1.3.14", "@types/node": "^24.10.0", "@types/react": "^19.3.0", "@types/react-dom": "^19.3.0", "bun-plugin-tailwind": "^0.1.2", "chalk": "^5.6.2", "chokidar": "^5.0.0", "commander": "^14.0.2", "esbuild": "^0.28.2", "lightningcss-wasm": "^1.32.0", "lodash": "^4.18.1", "ora": "^9.0.0", "postcss": "^8.5.30", "react": "^19.3.0", "react-dom": "^19.3.0", "tailwindcss": "^4.3.3", "typescript": "^5.0.0", "uuid": "^14.0.2" }, "bin": { "bunext": "dist/commands/index.js" } }, "sha512-Es59Dvq3/eF726+SOHPiKtlJ87UFmyJZI4gpeciW/fA/3ZwOWws2Mm3oD6eZnOj9BP/zlBKOWA9DPTl35IP3lg=="],
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.4.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-u2wAM9RzqyF4baO5oFVhcFUVWO1CCMLG6yC5/aPWCYGZPfL5ULMbeHt+0/3I0h3yaPx1m+PKSANO/61jPtDZcQ=="],
diff --git a/dev/package.json b/dev/package.json
index 2beb7a8..5484949 100644
--- a/dev/package.json
+++ b/dev/package.json
@@ -10,7 +10,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
- "@moduletrace/bunext": "^1.3.4",
+ "@moduletrace/bunext": "^1.3.5",
"lucide-react": "^1.59.0"
},
"devDependencies": {
diff --git a/dev/src/pages/elements.tsx b/dev/src/pages/elements.tsx
index fa186ed..96fffb6 100644
--- a/dev/src/pages/elements.tsx
+++ b/dev/src/pages/elements.tsx
@@ -195,6 +195,14 @@ export default function ElementsPage() {
Page {page} of {Math.ceil(42 / 5)}
+
+
+
diff --git a/dev/src/pages/forms.tsx b/dev/src/pages/forms.tsx
index a903758..31f2ad4 100644
--- a/dev/src/pages/forms.tsx
+++ b/dev/src/pages/forms.tsx
@@ -180,6 +180,31 @@ export default function FormsPage() {
{ value: "team", title: "Team" },
]}
/>
+
+
+
+
@@ -241,7 +266,7 @@ export default function FormsPage() {
? JSON.stringify(submitted, null, 2)
: "Submit the form to see the collected data."}
-
+
Checkbox and Toggle are div-based and are not
diff --git a/package.json b/package.json
index 734a018..64a02c1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@moduletrace/twui",
- "version": "0.1.9",
+ "version": "0.1.10",
"description": "A modular skeletal React component framework for Tailwind CSS v4",
"author": "Benjamin Toby",
"type": "module",
diff --git a/src/elements/Pagination.tsx b/src/elements/Pagination.tsx
index 7c92446..597739f 100644
--- a/src/elements/Pagination.tsx
+++ b/src/elements/Pagination.tsx
@@ -16,8 +16,9 @@ type Props = ComponentProps & {
/**
* # Pagination Component
- * @param param0
- * @returns
+ * Stays within its parent's width: the page buttons scroll horizontally
+ * when there are too many to fit.
+ * @className twui-pagination
*/
export default function Pagination({
count,
@@ -44,7 +45,7 @@ export default function Pagination({
}}
variant="outlined"
size="small"
- className="p-1"
+ className="p-1 shrink-0"
disabled={isLimit}
>
@@ -55,7 +56,7 @@ export default function Pagination({
@@ -68,7 +69,7 @@ export default function Pagination({
}}
variant="outlined"
size="small"
- className="p-1"
+ className="p-1 shrink-0"
disabled={page == 1}
>
@@ -79,20 +80,20 @@ export default function Pagination({
Page {page} / {pages}
{pages > 1 && (
{Array(pages)
diff --git a/src/form/Radios.tsx b/src/form/Radios.tsx
index 1f90d2d..715fd84 100644
--- a/src/form/Radios.tsx
+++ b/src/form/Radios.tsx
@@ -28,11 +28,23 @@ export type TWUI_FORM_RADIO_PROPS = {
>;
wrapperProps?: ComponentProps;
changeHandler?: (value: string) => void;
+ /**
+ * Let each radio's label wrap onto multiple lines. By default every
+ * radio stays on one line with its label clamped to a single line with
+ * an ellipsis, and the full text is shown as the radio's `title` on
+ * hover.
+ */
+ wrap?: boolean;
};
/**
* # Form Radios Component
- * @className twui-textarea
+ * @className twui-radios
+ * @className twui-radio
+ * @className twui-radio-label
+ * @className twui-radio-indicator - the custom circle; the native input is
+ * visually hidden right before it, so target the checked state with
+ * `.twui-radio input:checked + .twui-radio-indicator`
*/
export default function Radios({
values,
@@ -41,6 +53,7 @@ export default function Radios({
labelProps,
wrapperProps,
changeHandler,
+ wrap,
}: TWUI_FORM_RADIO_PROPS) {
const finalName = twuiSlugify(name);
const finalTitle = twuiSlugToNormalText(finalName);
@@ -49,26 +62,67 @@ export default function Radios({
{values.map((v, i) => {
const valueName = twuiSlugify(`${finalName}-${v.value}`);
const valueTitle = v.title || twuiSlugToNormalText(v.value);
return (
-
- {
- const targetValue = v.value;
- changeHandler?.(targetValue);
- }}
- {...inputProps}
- />
-