diff --git a/README.md b/README.md index 3bbbdfba..0aa0e457 100644 --- a/README.md +++ b/README.md @@ -117,8 +117,8 @@ The rules that hold across every component — worth two minutes before your fir flat. Parts are styleable via `data-slot` and state attributes such as `data-open`. - There is **no polymorphic `as` prop**. -Forms are TanStack Form plus any Standard Schema validator; Table is headless and assembled -from hooks. Both, with toasts, icons and dates, are covered in +Forms are built in and take any Standard Schema validator; DataGrid derives filtering, +sorting, pagination and selection itself. Both, with toasts, icons and dates, are covered in **[docs/ui-usage.md](https://github.com/pathscale/ui/blob/master/docs/ui-usage.md)**. ## Requirements @@ -137,8 +137,7 @@ line and must not be used. The complete compiler contract, hard-error behavior, commands, and porting analyzer are documented in [docs/layouts.md](docs/layouts.md). -Peers include `@solid-primitives/*`, `@tanstack/solid-form` and `@tanstack/solid-table`. -Two are optional and only needed for the features they back: `popmotion` (JS animation +Two peers are optional and only needed for the features they back: `popmotion` (JS animation driver) and `@standard-schema/spec` (schema validation). ## Subpath exports diff --git a/bun.lock b/bun.lock index 53b1c804..1c59e345 100644 --- a/bun.lock +++ b/bun.lock @@ -5,9 +5,8 @@ "": { "name": "@pathscale/ui", "dependencies": { - "@iconify/tailwind4": "^1.2.3", - "@pathscale/rsbuild-plugin-iconify": "^1.0.4", - "@tanstack/solid-virtual": "^3.13.27", + "@solidjs/web": "2.0.0-rc.0", + "clsx": "^2.1.1", "tailwind-merge": "^3.6.0", }, "devDependencies": { @@ -19,48 +18,24 @@ "@rsbuild/core": "^2.0.9", "@rsbuild/plugin-solid": "^1.2.1", "@rslib/core": "^0.22.0", - "@solid-primitives/event-listener": "^2.4.5", - "@solid-primitives/intersection-observer": "^2.2.4", - "@solid-primitives/keyboard": "^1.3.5", - "@solid-primitives/media": "^2.3.5", - "@solid-primitives/props": "^3.2.3", - "@solid-primitives/resize-observer": "^2.1.5", - "@solid-primitives/scheduled": "^1.5.3", - "@solid-primitives/scroll": "^2.1.5", - "@solid-primitives/storage": "^2.1.4", - "@solid-primitives/utils": "^6.4.0", + "@solidjs/h": "2.0.0-rc.0", "@standard-schema/spec": "^1.1.0", - "@tanstack/solid-form": "^1.33.0", - "@tanstack/solid-table": "^8.21.3", "@types/bun": "^1.3.14", "babel-preset-solid": "^1.9.12", "cally": "^0.8.0", - "clsx": "^2.1.1", "cssnano": "^7.1.9", "postcss": "^8.5.15", "postcss-cli": "^11.0.1", "postcss-selector-parser": "^7.1.1", - "rsbuild-plugin-solid-layouts": "^0.1.4", - "solid-js": "^1.9.14", - "solid-layouts": "^0.1.3", - "solid-layouts-oxc": "^0.1.7", + "rsbuild-plugin-solid-layouts": "0.2.1", + "solid-js": "2.0.0-rc.0", + "solid-layouts": "0.2.0", + "solid-layouts-oxc": "0.2.1", "svgo": "^3.3.3", "typescript": "^6.0.3", }, "peerDependencies": { - "@solid-primitives/event-listener": "^2.3.0", - "@solid-primitives/intersection-observer": "^2.1.3", - "@solid-primitives/keyboard": "^1.2.5", - "@solid-primitives/media": "^2.2.5", - "@solid-primitives/props": "^3.1.8", - "@solid-primitives/resize-observer": "^2.0.22", - "@solid-primitives/scheduled": "^1.4.1", - "@solid-primitives/scroll": "^2.0.20", - "@solid-primitives/storage": "^2.1.1", - "@solid-primitives/utils": "^6.2.1", "@standard-schema/spec": "^1.0.0", - "@tanstack/solid-form": "^1.29.0", - "@tanstack/solid-table": "^8.0.0", "popmotion": "^11.0.5", "solid-js": "^1.9", "solid-layouts": "^0.1.3", @@ -178,8 +153,6 @@ "@colordx/core": ["@colordx/core@5.4.3", "", {}, "sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ=="], - "@cyberalien/svg-utils": ["@cyberalien/svg-utils@1.2.15", "", { "dependencies": { "@iconify/types": "^2.0.0" } }, "sha512-ZbKU6npzW5PNocdoLVJYfKzaP+c/RpT6JUkoaKrW1DOcw6lyXub8XtcNpI3xok6FnyNjS6ZbsrrtjTnS9yeZAQ=="], - "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], @@ -188,10 +161,6 @@ "@iconify/json": ["@iconify/json@2.2.481", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.3" } }, "sha512-H/bCPJN+JawFnEgSFtBGQMz2nAc3KNsLZ6fKG6KfJX7X9H0blv0Acbt6umCBVRxZ0xBM/9FcUYZst4/Zv6SB/A=="], - "@iconify/tailwind4": ["@iconify/tailwind4@1.2.3", "", { "dependencies": { "@iconify/tools": "^5.0.5", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0" }, "peerDependencies": { "tailwindcss": ">= 4.0.0" } }, "sha512-z8SKiMHRASJKF/IY//87MF88lcB7ulxh8vlhQXXLWsBkNtOh6ese9R41MyGpQeqXdRvQVt+/fX2glQtHFjQ+MA=="], - - "@iconify/tools": ["@iconify/tools@5.0.12", "", { "dependencies": { "@cyberalien/svg-utils": "^1.2.15", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.3", "fflate": "^0.8.3", "modern-tar": "^0.7.6", "pathe": "^2.0.3", "svgo": "^4.0.1" } }, "sha512-aFPwSFmFphUPVjNLUkgxgUPSPVgTEEjv0mE7NgvfoQBuE5TtsMrKa4HTY65cM5oXZ2a1xKQcW/RKhiOKEiAarw=="], - "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], "@iconify/utils": ["@iconify/utils@2.3.0", "", { "dependencies": { "@antfu/install-pkg": "^1.0.0", "@antfu/utils": "^8.1.0", "@iconify/types": "^2.0.0", "debug": "^4.4.0", "globals": "^15.14.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "mlly": "^1.7.4" } }, "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA=="], @@ -220,8 +189,6 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], - "@pathscale/rsbuild-plugin-iconify": ["@pathscale/rsbuild-plugin-iconify@1.0.4", "", { "dependencies": { "@iconify/json": "^2.2.481", "@iconify/utils": "^2.3.0", "@rspack/core": "^1.7.11", "cssnano": "^7.1.9", "postcss": "^8.5.15", "postcss-cli": "^11.0.1", "svgo": "^3.3.3" }, "peerDependencies": { "@rsbuild/core": "^1.3.22", "@rslib/core": "^0.9.1" } }, "sha512-KrCuzAa9AzbXojh7ne+yfldfipWZ39d/BFfwDhLNlDvQxpena5I/0h4eoa4x4RlaCux6h+Ay81KmHGrdR0tpyw=="], - "@pathscale/rsbuild-plugin-ui-css-purge": ["@pathscale/rsbuild-plugin-ui-css-purge@0.9.11", "", { "dependencies": { "@swc/core": "^1.15.40", "lightningcss": "^1.32.0", "postcss": "^8.5.15" }, "bin": { "rsbuild-plugin-ui-css-purge": "dist/postbuild-purge.js", "generate-manifest": "src/generate-manifest.ts" } }, "sha512-iIyScjlJ1/yfbtD+vPWQP+S5WSQp6tBtppDAMGImBPCxzoSnpQPwhvsyFGpNyVwGUZj/8QxhbpY34ev0FXKpng=="], "@rsbuild/core": ["@rsbuild/core@2.0.9", "", { "dependencies": { "@rspack/core": "~2.0.5", "@swc/helpers": "^0.5.23" }, "peerDependencies": { "core-js": ">= 3.0.0" }, "optionalPeers": ["core-js"], "bin": { "rsbuild": "./bin/rsbuild.js" } }, "sha512-lK2bMNuwh3TuLXLskS7nG3fnQk+6eaLeeZiquJWcna4JZx9iaI59JSd+iLcg5TeZLjEVygkwn/HcE+yuYDQRAw=="], @@ -256,31 +223,11 @@ "@rspack/core": ["@rspack/core@2.0.5", "", { "dependencies": { "@rspack/binding": "2.0.5" }, "peerDependencies": { "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", "@swc/helpers": "^0.5.23" }, "optionalPeers": ["@module-federation/runtime-tools", "@swc/helpers"] }, "sha512-9tv2HAnSiTote5WPH2tmz1hLZ1zKbzkiZc1eYp7LP/8jcsiJBuf40ihiWidAgbbuYtJo3kWET6q+qOm5UhNiGA=="], - "@rspack/lite-tapable": ["@rspack/lite-tapable@1.1.0", "", {}, "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw=="], - - "@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.5", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-nwRV558mIabl4yVAhZKY8cb6G+O1F0M6Z75ttTu5hk+SxdOnKSGj+eetDIu7Oax1P138ZdUU01qnBPR8rnxaEA=="], - - "@solid-primitives/intersection-observer": ["@solid-primitives/intersection-observer@2.2.4", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-3+QaAT/TUdEaeKkqiTf+sk8g1/vE+QM9PucG2/JI8hLI8ALpBYBnlhtvcwIdpjaKMSpPN/1L4hneLvwqnx4YRA=="], - - "@solid-primitives/keyboard": ["@solid-primitives/keyboard@1.3.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-sav+l+PL+74z3yaftVs7qd8c2SXkqzuxPOVibUe5wYMt+U5Hxp3V3XCPgBPN2I6cANjvoFtz0NiU8uHVLdi9FQ=="], - - "@solid-primitives/media": ["@solid-primitives/media@2.3.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/static-store": "^0.1.3", "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-LX9fB5WDaK87FMDtUB1qokBOfT2et9Uobv/zZaKLH9caFSz4+P70MBKEIBHcZQy+9MV5M2XvGYLTbLskjkzMjA=="], - - "@solid-primitives/props": ["@solid-primitives/props@3.2.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-XzG6en9gSFwmvbKcATm2BxL63HegZ+BAG5fmHi8jyBppQHcaths7ffz+6vYvwYy3nlgLa20ufJLj7tst+PcHFA=="], - - "@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/static-store": "^0.1.3", "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AiyTknKcNBaKHbcSMuxtSNM8FjIuiSuFyFghdD0TcCMU9hKi9EmsC5pjfjDwxE+5EueB1a+T/34PLRI5vbBbKw=="], + "@solidjs/h": ["@solidjs/h@2.0.0-rc.0", "", { "peerDependencies": { "@solidjs/web": "^2.0.0-rc.0" } }, "sha512-APPxIiLi7E0JME1RDkwvkwhjgk5PB6wg81aZ8lqGxb+ljqLgTogCK30E9K3BHJTk/qnWGlvOHbVvmgGf3s2fZQ=="], - "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], + "@solidjs/signals": ["@solidjs/signals@2.0.0-rc.0", "", {}, "sha512-oKZSfvsCcKw1uJjOGbUkJ+OqlhXLHtZ+rShSyu9KH0lUH7UUwfMfsKeh81JPiQxDDg4YLhEwI38hg0JkwzTdvA=="], - "@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.3", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-oNwLE6E6lxJAWrc8QXuwM0k2oU1BnANnkChwMw82aK1j3+mWGJkG1IFe5gCwbV+afYmjI76t9JJV3md/8tLw+g=="], - - "@solid-primitives/scroll": ["@solid-primitives/scroll@2.1.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/static-store": "^0.1.3" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-G7t4Kt1E+f4d7iZ2dGDWsra2k1WQ5VOtXrTcg7MC+DrR5QMq8YCj9wB/C9yxHJ1lGi7Sv+mzjNLtVCFO5ECzUg=="], - - "@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-uxez7SXnr5GiRnzqO2IEDjOJRIXaG+0LZLBizmUA1FwSi+hrpuMzVBwyk70m4prcl8X6FDDXUl9O8hSq8wHbBQ=="], - - "@solid-primitives/storage": ["@solid-primitives/storage@2.1.4", "", { "dependencies": { "@solid-primitives/utils": "^6.2.3" }, "peerDependencies": { "solid-js": "^1.6.12", "solid-start": ">=0.2.26" }, "optionalPeers": ["solid-start"] }, "sha512-ziGRMSPi2PDnY6L6YPGWYnzmUEPIwO0PaDT9N1WNW9P2tUMMhgqKLXBrYfjytpjwY3UM6kIrbONMRADjyGtzAw=="], - - "@solid-primitives/utils": ["@solid-primitives/utils@6.4.0", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A=="], + "@solidjs/web": ["@solidjs/web@2.0.0-rc.0", "", { "dependencies": { "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" }, "peerDependencies": { "solid-js": "^2.0.0-rc.0" } }, "sha512-pYSaA9+dH8H1h/d/ZF/P2kR6omfzFGNcdzKhWTcg9fJghXhn8+5UrXUr2iYxDdYNOXZzxxFQhYHSJ7P4HKDqgw=="], "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], @@ -316,26 +263,6 @@ "@swc/types": ["@swc/types@0.1.26", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw=="], - "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.4.3", "", { "bin": { "intent": "bin/intent.js" } }, "sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw=="], - - "@tanstack/form-core": ["@tanstack/form-core@1.33.0", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.1", "@tanstack/pacer-lite": "^0.1.1", "@tanstack/store": "^0.11.0" } }, "sha512-AV4Pw9Dk4orFsuPBcDssfWMJFs+yMYBae7zZ4oTqrCf4ftNGQKxvrQRZeqKHG6A4TkiLeSvf2kzIjcVkrW7E6w=="], - - "@tanstack/pacer-lite": ["@tanstack/pacer-lite@0.1.1", "", {}, "sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w=="], - - "@tanstack/solid-form": ["@tanstack/solid-form@1.33.0", "", { "dependencies": { "@tanstack/form-core": "1.33.0", "@tanstack/solid-store": "^0.11.0" }, "peerDependencies": { "solid-js": ">=1.9.9" } }, "sha512-+KXp+T/fD+nO5JarDj1W5GctEm4aFuz13DkHVJrdIHGo0evMXlFNWJT57n+TOyvoLoKehknKjM1o41rrKClSTQ=="], - - "@tanstack/solid-store": ["@tanstack/solid-store@0.11.0", "", { "dependencies": { "@tanstack/store": "0.11.0" }, "peerDependencies": { "solid-js": "^1.6.0" } }, "sha512-2isL0ZnnyI1iN0V+QPrxE3OcPndohBgVlBcHZYoAOIAiU1WoWjVy0q5gb0suPu1Id0h5cKC23JnwzQTxWDZD0w=="], - - "@tanstack/solid-table": ["@tanstack/solid-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "solid-js": ">=1.3" } }, "sha512-PmhfSLBxVKiFs01LtYOYrCRhCyTUjxmb4KlxRQiqcALtip8+DOJeeezQM4RSX/GUS0SMVHyH/dNboCpcO++k2A=="], - - "@tanstack/solid-virtual": ["@tanstack/solid-virtual@3.13.27", "", { "dependencies": { "@tanstack/virtual-core": "3.16.1" }, "peerDependencies": { "solid-js": "^1.3.0" } }, "sha512-pQZJa2IOR1rr76A1l4wV4iY1mrku6B8otNGw2hg1ywKCrbl74y50AbpPYR06ziMOjGjrGZBBAdTk+VY9IJON6w=="], - - "@tanstack/store": ["@tanstack/store@0.11.0", "", {}, "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw=="], - - "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], - - "@tanstack/virtual-core": ["@tanstack/virtual-core@3.16.1", "", {}, "sha512-br4gmJ3eI2IXth0fAAVWNdi/Iqb5ZDIUG9409Q17qnXegeHHc9vPEeMsSwpGf29GqayfmqFPtv9S4rxcZOub3Q=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -444,8 +371,6 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], @@ -464,8 +389,6 @@ "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], - "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -524,8 +447,6 @@ "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], - "modern-tar": ["modern-tar@0.7.6", "", {}, "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg=="], - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], @@ -630,7 +551,7 @@ "rsbuild-plugin-dts": ["rsbuild-plugin-dts@0.22.0", "", { "dependencies": { "@ast-grep/napi": "0.37.0" }, "peerDependencies": { "@microsoft/api-extractor": "^7", "@rsbuild/core": "^1.0.0 || ^2.0.0-0", "@typescript/native-preview": "7.x", "typescript": "^5 || ^6" }, "optionalPeers": ["@microsoft/api-extractor", "@typescript/native-preview", "typescript"] }, "sha512-Oyiu5oJDHWOnBv7yRr8eAGfoEddwxfPqUbAX6HvcJxrnR/h6Zd0VgTBWVTgqALYhLcL2ZdyZ2vwnqfhan4krwA=="], - "rsbuild-plugin-solid-layouts": ["rsbuild-plugin-solid-layouts@0.1.4", "", { "dependencies": { "solid-layouts-oxc": "0.1.7" }, "peerDependencies": { "@rsbuild/core": ">=1.3.0" } }, "sha512-6FgOrK2e9u8Bueb26AUVUAw5eE4zLMis8eA6dtF0tl+vByZEksQIUtkEHvNO17ki8sodoyOrMt+M1HFivNEZUg=="], + "rsbuild-plugin-solid-layouts": ["rsbuild-plugin-solid-layouts@0.2.1", "", { "dependencies": { "solid-layouts-oxc": "^0.2.1" }, "peerDependencies": { "@rsbuild/core": ">=1.3.0" } }, "sha512-BUUC6P3wvLPowWCkRZj/82PXaHMLxLNg7FgQFWiR6AU0VrH9MFGKT8f83GCNdwBUHYjymZ1EX31SxZQ3KDu5NA=="], "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], @@ -642,11 +563,11 @@ "slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="], - "solid-js": ["solid-js@1.9.14", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-sAEXC0Kk0S1EDg+8ysEWJDbYhA3RRoEjwuySUGlKIemeo0I5YZfOyumNjNs9Sv3y2nmhD+0rW66ag2HsMuQiGQ=="], + "solid-js": ["solid-js@2.0.0-rc.0", "", { "dependencies": { "@solidjs/signals": "^2.0.0-rc.0", "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-3enTJ71VL69nM5p/it2InVBDBt316Cqfij+F0S7VuHZLITc8YV7Rvavjoy52nAKKxYWXM+BcXh2K7KcLTf1zdQ=="], - "solid-layouts": ["solid-layouts@0.1.3", "", { "peerDependencies": { "solid-js": "^1.9.14" } }, "sha512-SDlahgR/wbVA7x6M7Vgm1XqIShJ/1JeN0Kvbf4TZqj3CAZDjaTugkoJBogfg14+/Kfnh0BZ+86QFwjcXzMrpXA=="], + "solid-layouts": ["solid-layouts@0.2.0", "", { "peerDependencies": { "@solidjs/web": "^2.0.0-rc.0", "solid-js": "^1.9.14 || ^2.0.0-rc.0" }, "optionalPeers": ["@solidjs/web"] }, "sha512-O+tHZsxFp00g2rXtOPdDFwWgdGBKoG31z6l6RJyT1Zab5KPckIg5m6zBBMakzTdZqMLeSsA5N4FZ23gAYzJkOA=="], - "solid-layouts-oxc": ["solid-layouts-oxc@0.1.7", "", { "bin": { "solid-layouts-library": "bin/solid-layouts-library.js", "solid-layouts-application": "bin/solid-layouts-application.js", "solid-layouts-lint": "bin/solid-layouts-lint.js" } }, "sha512-1rVht4oKW6SnW8uHjXBVWUb3jr8GwuUH+23T3UCvqj+HaWfBlWtgseefTMWf9qlAVDjX5BGE2V/kNV4gHxcGpg=="], + "solid-layouts-oxc": ["solid-layouts-oxc@0.2.1", "", { "bin": { "solid-layouts-library": "bin/solid-layouts-library.js", "solid-layouts-application": "bin/solid-layouts-application.js", "solid-layouts-lint": "bin/solid-layouts-lint.js" } }, "sha512-u245kTqsNzYOEwpKxaTQOIubOgkXBQDuwP7xKzQ8MNFMHsNP6FrgtTA0tEf5UcUcE+WEyjl17VRRKnmUChat2w=="], "solid-refresh": ["solid-refresh@0.7.8", "", { "dependencies": { "@babel/generator": "^7.29.1", "@babel/types": "^7.29.0" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-iG442T3HXJp5jEebCy8okETrWnmX7CnxNOKrJQVeufh6WXSn+xtLXaptUXXMHTWcRqTJOJwQ8UwzxrRtVFSIzA=="], @@ -662,8 +583,6 @@ "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], - "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], - "thenby": ["thenby@1.4.1", "", {}, "sha512-D5a/bO0KdalOE3q8MlrRmSxjbKZHT3MQmXkJP+r97Vw8MMwOZKOwUSEyTtK7eSMj2y0kyAjpYMRMZmmLw1FtNQ=="], "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], @@ -698,14 +617,6 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "@iconify/tailwind4/@iconify/utils": ["@iconify/utils@3.1.3", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "import-meta-resolve": "^4.2.0" } }, "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw=="], - - "@iconify/tools/@iconify/utils": ["@iconify/utils@3.1.3", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "import-meta-resolve": "^4.2.0" } }, "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw=="], - - "@iconify/tools/svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core": ["@rspack/core@1.7.11", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.11", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew=="], - "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], @@ -720,12 +631,6 @@ "readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "@iconify/tools/svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], - - "@iconify/tools/svgo/css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding": ["@rspack/binding@1.7.11", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.11", "@rspack/binding-darwin-x64": "1.7.11", "@rspack/binding-linux-arm64-gnu": "1.7.11", "@rspack/binding-linux-arm64-musl": "1.7.11", "@rspack/binding-linux-x64-gnu": "1.7.11", "@rspack/binding-linux-x64-musl": "1.7.11", "@rspack/binding-wasm32-wasi": "1.7.11", "@rspack/binding-win32-arm64-msvc": "1.7.11", "@rspack/binding-win32-ia32-msvc": "1.7.11", "@rspack/binding-win32-x64-msvc": "1.7.11" } }, "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q=="], - "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], @@ -734,30 +639,6 @@ "postcss-svgo/svgo/css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], - "@iconify/tools/svgo/css-tree/mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.11", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.11", "", { "os": "win32", "cpu": "x64" }, "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q=="], - "postcss-svgo/svgo/css-tree/mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], - - "@pathscale/rsbuild-plugin-iconify/@rspack/core/@rspack/binding/@rspack/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], } } diff --git a/docs/api-contract.md b/docs/api-contract.md index 49a165f4..46c81068 100644 --- a/docs/api-contract.md +++ b/docs/api-contract.md @@ -270,7 +270,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### DialogContent -`backdrop children isDismissable placement scrollBehavior shouldCloseOnBackdropClick size` +`backdrop children isDismissable material placement scrollBehavior shouldCloseOnBackdropClick size` ### DialogFooter @@ -318,7 +318,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### DrawerContent -`children placement scrollBehavior` +`children material placement scrollBehavior` ### DrawerDialog @@ -422,7 +422,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### InputOTP -`autoFocus children defaultValue disabled inputClassName inputMode issues maxLength name onChange onComplete pattern state value variant` +`autoFocus children defaultValue disabled inputClassName inputmode issues maxLength name onChange onComplete pattern state value variant` ### InputOTPGroup @@ -494,7 +494,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### Menu -`children defaultSelectedKeys disabled disabledKeys disallowEmptySelection items onAction onSelectionChange renderEmpty selectedKeys selectionMode state` +`children defaultSelectedKeys disabled disabledKeys disallowEmptySelection items material onAction onSelectionChange renderEmpty selectedKeys selectionMode state` ### MenuItem @@ -534,7 +534,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### Navbar -`as dataTheme` +`as dataTheme material` ### NoiseBackground @@ -634,7 +634,7 @@ HTML attributes and `UIBaseProps`; that is an assertion, not a gap. ### TableVirtualSpacerRow -`colSpan height` +`colspan height` ### Tabs diff --git a/docs/ui-usage.md b/docs/ui-usage.md index 2bd6e860..eadca7b8 100644 --- a/docs/ui-usage.md +++ b/docs/ui-usage.md @@ -31,10 +31,44 @@ Layout components require the application compiler before the normal Solid trans ## Theming - Two themes: `light` (default when no attribute) and `dark`. Switch: `document.documentElement.setAttribute("data-theme", "dark")`. -- Tokens are CSS vars: `--color-primary(/-content)`, `--color-secondary`, `--color-accent`, `--color-neutral`, `--color-info/success/warning/error`, `--color-danger`, surfaces `--color-base-100/200/300`, `--color-base-content`, HeroUI-style `--color-default(/-foreground/-hover)`, `--color-background/foreground`, daisy short aliases `--b1/--b2/--b3/--bc`, radii `--radius-selector/-field/-box`, and a ~35-var `--glass-*` set (runtime-tweakable on `documentElement.style`). +- Tokens are CSS vars: `--color-primary(/-content)`, `--color-secondary`, `--color-accent`, `--color-neutral`, `--color-info/success/warning/error`, `--color-danger`, surfaces `--color-base-100/200/300`, `--color-base-content`, HeroUI-style `--color-default(/-foreground/-hover)`, `--color-background/foreground`, daisy short aliases `--b1/--b2/--b3/--bc`, radii `--radius-selector/-field/-box`, and the `--glass-*` set: six colours the theme owns, plus the rest derived from three numbers by `applyGlassTokens` (see [Glass](#glass)). - `src/index.css` has a Tailwind v4 `@theme` block, so in a Tailwind v4 app `bg-primary`, `text-base-content`, `bg-base-100` etc. work. - Any component accepts `dataTheme` prop → rendered as `data-theme` attr (scoped theming). +### Glass + +`material="glass"` makes a surface out of what is behind it rather than a fill. +It is on `Card`, `Dialog.Content`, `Drawer.Content`, `Popover.Content`, `Menu` +and `Navbar`; `solid` is the default everywhere, so nothing changes until it is +asked for. + +The look is driven by the `--glass-*` custom properties, and you do not set +those by hand — `applyGlassTokens` derives all twenty-five from three numbers: + +```ts +import { applyGlassTokens, GLASS_DEFAULTS, GLASS_LIMITS } from "@pathscale/ui"; + +applyGlassTokens({ blur: 9, refraction: 0.31, depth: 24 }, "dark"); +``` + +- `blur` (0–50px) how far the backdrop is smeared +- `refraction` (0–0.4) how much the surface asserts its own tint, border and highlight +- `depth` (0–30) how far off the page it sits: glow, sheen, shadow + +`GLASS_LIMITS` carries those ranges and `GLASS_DEFAULTS` the per-mode defaults, +so a settings panel should read both from here rather than restating them. +`resolveGlassTokens` returns the same set as an object, and `glassTokensToCss` +as a declaration block for a theme that wants them baked in. + +Pass a **complete** tuning. Three of the derived tokens are read without a CSS +fallback, and an undefined custom property makes CSS drop the whole declaration +rather than fall back — so a partial set renders a surface with no background at +all rather than a plainer one. + +Nested glass is flattened to one pane on purpose, and both +`prefers-reduced-transparency` and a browser without `backdrop-filter` fall back +to a more opaque fill. + ## Component conventions (consumer-facing) - Booleans are HeroUI-style `is*`: `isDisabled`, `isOpen`, `isInvalid`, `isPending`, `isIconOnly`, `isHoverable`, `isPressable`. Native `disabled` also honored. @@ -92,7 +126,7 @@ the shared fallback. This works with PathScale Fonts and application-owned font ## Component inventory (by family) -- **Layout/primitives**: Flex, Grid, Join, Surface, Card, GlassPanel, Separator, ScrollShadow, Skeleton, EmptyState, Footer, Header, Navbar, Toolbar, FloatingDock +- **Layout/primitives**: Flex, Grid, Join, Card, Separator, ScrollArea, Skeleton, Empty, Footer, Header, Navbar, Toolbar, Dock - **Typography/misc**: Text, Link, Kbd, Badge, Chip, Tag/TagGroup, Avatar, Icon, Tooltip, Breadcrumbs, Pagination, Meter, ProgressBar, ProgressCircle, Spinner (alias: Loading) - **Inputs**: Input, InputGroup, InputOTP, TextField, TextArea (and textarea), NumberField, SearchField, PasswordField (+ password-requirements/rules, `passwordRules.ts`), ColorField, Checkbox(+Group), Radio(+Group), Toggle, Slider, Select, ComboBox, ListBox, SizePicker, Form pieces (Label, Description, ErrorMessage, FieldError, Fieldset) - **Dates**: Calendar, RangeCalendar, DatePicker, DateRangePicker (internal date engine); DateField, TimeField (separate segmented editors) @@ -112,7 +146,7 @@ the same normalized hex that it displays. Surface strength, softness and accent remain consumer theme concerns; use the literal selected hex as their input rather than making the wheel silently transform it. -## Forms (TanStack Form + Standard Schema) +## Forms (built in, plus Standard Schema) ```tsx import { createForm, Form, FormField, FormSubmitButton } from "@pathscale/ui"; @@ -131,8 +165,8 @@ const form = createForm({ ``` - `Form` without a `form` prop = plain styled `
` (`FormRoot`). With `form` = context provider + wired submit. -- Inside a ``: `useField(name)` → `{value, error, touched, invalid, handleChange, handleBlur}`. **Errors are touch-gated** — `error()` is `undefined` until the field blurs. `FormSubmitButton` disables on `!canSubmit` (not touch-gated), so the button can be disabled with no visible error. -- Escape hatch: `form._tsForm` is the raw TanStack form API (typed `any` on purpose). +- Inside a ``: `useField(name)` → `{value, error, touched, invalid, handleChange, handleBlur}`. **Errors are touch-gated** — `error()` is `undefined` until the field blurs. `FormSubmitButton` disables on `!form.isValid()` (not touch-gated), so the button can be disabled with no visible error. A failed `submit()` touches every field, so the errors it refused on all become visible at once. +- The form API is the library's own: `values()`, `getFieldValue`, `getFieldMeta`, `setFieldValue`, `validateField`, `submit()`, `isSubmitting()`, `isValid()`. There is no longer a `_tsForm` escape hatch, because there is no longer a wrapped library to escape to. - Schema validation runs on change+blur+submit; blur errors clear immediately on change once valid. ## DataGrid (assembled) @@ -216,7 +250,7 @@ const table = useTableModel({ - State-slice hooks (all controlled-or-uncontrolled): `useTableSorting`, `useTableSelection`, `useTableFiltering` (per-column popovers + `getColumnFilterProps`), `useTablePagination` (⚠️ `nextPage(max)`/`lastPage(max)` need caller-supplied max page index), `useTableExpansion`. - Parts: TableRoot/ScrollContainer/Content/Header/Column/Body/Row/Cell/ExpandedRow/Footer/PageSize/ResizableContainer/ColumnResizer/LoadMore(+Content), plus SortIcon, ExpandToggle, InlineConfirm, MobileListView (responsive card fallback), VirtualSpacerRow. -- **Virtualization is not built in**: combine `useVirtualRows` (wraps @tanstack/solid-virtual) + `VirtualSpacerRow` yourself. See the Table section above. +- **Virtualization is not built in.** `useVirtualRows` was a thin wrapper over `@tanstack/solid-virtual` that nothing in the library used; it was removed with the rest of TanStack. `VirtualSpacerRow` is still here for a caller that brings its own windowing. ## Motion diff --git a/layouts.library.json b/layouts.library.json index 06383c21..6f782548 100644 --- a/layouts.library.json +++ b/layouts.library.json @@ -1,5 +1,6 @@ { "mode": "source", + "solid": 2, "source": "src/components", "output": "dist", "exports": [ diff --git a/package.json b/package.json index 5d0fbb2e..3e5c49f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pathscale/ui", - "version": "2.5.0", + "version": "2.6.0", "author": "pathscale", "repository": { "type": "git", @@ -73,19 +73,8 @@ "@rsbuild/core": "^2.0.9", "@rsbuild/plugin-solid": "^1.2.1", "@rslib/core": "^0.22.0", - "@solid-primitives/event-listener": "^2.4.5", - "@solid-primitives/intersection-observer": "^2.2.4", - "@solid-primitives/keyboard": "^1.3.5", - "@solid-primitives/media": "^2.3.5", - "@solid-primitives/props": "^3.2.3", - "@solid-primitives/resize-observer": "^2.1.5", - "@solid-primitives/scheduled": "^1.5.3", - "@solid-primitives/scroll": "^2.1.5", - "@solid-primitives/storage": "^2.1.4", - "@solid-primitives/utils": "^6.4.0", + "@solidjs/h": "2.0.0-rc.0", "@standard-schema/spec": "^1.1.0", - "@tanstack/solid-form": "^1.33.0", - "@tanstack/solid-table": "^8.21.3", "@types/bun": "^1.3.14", "babel-preset-solid": "^1.9.12", "cally": "^0.8.0", @@ -93,32 +82,20 @@ "postcss": "^8.5.15", "postcss-cli": "^11.0.1", "postcss-selector-parser": "^7.1.1", - "rsbuild-plugin-solid-layouts": "^0.1.4", - "solid-js": "^1.9.14", - "solid-layouts": "^0.1.3", - "solid-layouts-oxc": "^0.1.7", + "rsbuild-plugin-solid-layouts": "0.2.1", + "solid-js": "2.0.0-rc.0", + "solid-layouts": "0.2.0", + "solid-layouts-oxc": "0.2.1", "svgo": "^3.3.3", "typescript": "^6.0.3" }, "dependencies": { + "@solidjs/web": "2.0.0-rc.0", "clsx": "^2.1.1", - "@tanstack/solid-virtual": "^3.13.27", "tailwind-merge": "^3.6.0" }, "peerDependencies": { - "@solid-primitives/event-listener": "^2.3.0", - "@solid-primitives/intersection-observer": "^2.1.3", - "@solid-primitives/keyboard": "^1.2.5", - "@solid-primitives/media": "^2.2.5", - "@solid-primitives/props": "^3.1.8", - "@solid-primitives/resize-observer": "^2.0.22", - "@solid-primitives/scheduled": "^1.4.1", - "@solid-primitives/scroll": "^2.0.20", - "@solid-primitives/storage": "^2.1.1", - "@solid-primitives/utils": "^6.2.1", "@standard-schema/spec": "^1.0.0", - "@tanstack/solid-form": "^1.29.0", - "@tanstack/solid-table": "^8.0.0", "popmotion": "^11.0.5", "solid-js": "^1.9", "solid-layouts": "^0.1.3" diff --git a/scripts/check-contracts.ts b/scripts/check-contracts.ts index 34ce978e..4a892f31 100644 --- a/scripts/check-contracts.ts +++ b/scripts/check-contracts.ts @@ -118,6 +118,33 @@ if ( ); } +// --- Stale generated output --- +// +// `*.generated.tsx` is gitignored and written by `layouts:generate`, which only +// ever adds. Deleting a component therefore leaves its generated file behind, +// still importing the `.recipe` and `.layout` that went with it, and every +// build from then on fails inside a file nobody can see in `git status`. +// +// That is exactly how 2.5.0 shipped: twenty-two deleted components left +// twenty-two orphans, `bun run check` reported them as "missing index.ts +// barrel export" for components that no longer exist, and `bun run build` died +// generating declarations. Caught here it names the real problem and the fix. +for (const entry of readdirSync(COMPONENTS_DIR, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const dir = join(COMPONENTS_DIR, entry.name); + for (const file of readdirSync(dir)) { + if (!file.endsWith(".generated.tsx")) continue; + const authored = join(dir, file.replace(/\.generated\.tsx$/, ".layout.tsx")); + if (existsSync(authored)) continue; + fail( + entry.name, + "stale-generated", + `${join(dir, file)} has no .layout.tsx source; delete it (it is gitignored build output from a component that was removed)`, + "Structure", + ); + } +} + // --- Report --- if (violations.length === 0) { diff --git a/src/components/_shared/material.css b/src/components/_shared/material.css new file mode 100644 index 00000000..a970217d --- /dev/null +++ b/src/components/_shared/material.css @@ -0,0 +1,115 @@ +/* + * `material="glass"`, for every surface that can hold content. + * + * One definition rather than one per component. Card had these rules inline, + * and copying them to Dialog, Drawer, Popover, Menu, Dock and Navbar would be + * six places to update when the glass vocabulary moves — which it did once + * already, from thirty-one hand-declared properties to three numbers and + * twenty-five derived ones. + * + * A component opts in by importing this file and adding the `material` axis to + * its recipe. The classes are keyed on a data attribute rather than a + * `--material-glass` class so the rules are genuinely shared: a + * per-component class name would need this block duplicated for each one, which + * is the thing being avoided. + * + * Every `--glass-*` read carries a fallback, and that is load-bearing rather + * than tidy. An undefined custom property does not fall back to its initial + * value: CSS drops the whole declaration. Three of these used to be read bare, + * so a theme that defined twenty-eight of the thirty-one glass tokens got a + * surface with no background at all rather than a plainer one. The two shipped + * themes both use `white` for the three colours, so that is what the fallbacks + * say. `src/styles/glass.ts` derives the rest from `blur`, `refraction` and + * `depth`. + */ + +@layer components { + [data-material="solid"] { + backdrop-filter: none; + -webkit-backdrop-filter: none; + } + + [data-material="glass"] { + background-color: color-mix( + in oklab, + var(--glass-background-color, white), + transparent calc(100% - var(--glass-background-opacity, 55%)) + ); + border-color: color-mix( + in oklab, + var(--glass-border-color, white), + transparent calc(100% - var(--glass-border-opacity, 12%)) + ); + backdrop-filter: blur(var(--glass-blur, 50px)) saturate(var(--glass-saturation, 1.2)) + brightness(var(--glass-brightness, 1)); + -webkit-backdrop-filter: blur(var(--glass-blur, 50px)) saturate(var(--glass-saturation, 1.2)) + brightness(var(--glass-brightness, 1)); + } + + /* + * The inner highlight: the lit top edge that makes a pane read as a pane + * rather than as a translucent rectangle. + * + * On a pseudo-element so it cannot be overwritten by a component's own + * `box-shadow`, which is how elevation is expressed. `inherit` on the radius + * keeps it aligned to whatever corner the component chose. + */ + [data-material="glass"]::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; + box-shadow: inset 0 var(--border, 1px) 0 0 + color-mix( + in oklab, + var(--glass-highlight-color, white), + transparent calc(100% - var(--glass-highlight-opacity, 18%)) + ); + } + + /* + * Glass inside glass is one pane, not two. + * + * A backdrop filter reads the pixels behind it, so nesting one inside another + * blurs already-blurred output. That is muddy rather than deeper, and it + * costs a second render pass to get there. + */ + [data-material="glass"] [data-material="glass"] { + backdrop-filter: none; + -webkit-backdrop-filter: none; + } + + /* + * No backdrop support, or a reader who asked for less transparency. + * + * Falls back to a more opaque fill rather than to a thin tint over whatever + * happens to be behind it, because the tint alone is unreadable. The + * highlight goes too: it reads as a stray line without the material. + */ + @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + [data-material="glass"] { + background-color: color-mix( + in oklab, + var(--glass-background-color, white), + transparent calc(100% - var(--glass-fallback-background-opacity, 78%)) + ); + } + } + + @media (prefers-reduced-transparency: reduce) { + [data-material="glass"] { + background-color: color-mix( + in oklab, + var(--glass-background-color, white), + transparent calc(100% - var(--glass-fallback-background-opacity, 78%)) + ); + backdrop-filter: none; + -webkit-backdrop-filter: none; + } + + [data-material="glass"]::before { + box-shadow: none; + } + } +} diff --git a/src/components/_shared/overlayPosition.ts b/src/components/_shared/overlayPosition.ts index aecb122d..db2f1b6e 100644 --- a/src/components/_shared/overlayPosition.ts +++ b/src/components/_shared/overlayPosition.ts @@ -1,10 +1,5 @@ -import { - createEffect, - createSignal, - onCleanup, - type Accessor, - type JSX, -} from "solid-js"; +import {createEffect, createSignal, onCleanup, type Accessor} from "solid-js"; +import type { JSX } from "@solidjs/web"; export type OverlayPlacement = "top" | "bottom" | "left" | "right"; export type OverlayAlign = "start" | "center" | "end"; diff --git a/src/components/accordion/Accordion.layout.tsx b/src/components/accordion/Accordion.layout.tsx index 7c231f7e..e1094b90 100644 --- a/src/components/accordion/Accordion.layout.tsx +++ b/src/components/accordion/Accordion.layout.tsx @@ -1,17 +1,7 @@ import "./Accordion.css"; -import { - Show, - createContext, - createMemo, - createSignal, - createUniqueId, - splitProps, - useContext, - type Component, - type JSX, - type ParentComponent, -} from "solid-js"; -import { twMerge } from "tailwind-merge"; +import type { JSX } from "@solidjs/web"; +import {Show, createContext, createMemo, createSignal, createUniqueId, omit, useContext, type Component, type ParentComponent} from "solid-js"; +import { twMerge } from "../../lib/twMerge"; import type { UIBaseProps, State } from "../vocabulary"; import { CLASSES } from "./Accordion.recipe"; @@ -113,7 +103,8 @@ export type AccordionIndicatorProps = Omit, }; const AccordionRoot: Layout = () => { - const [local, others] = splitProps(props, [ + const others = omit( + props, "children", "class", "dataTheme", @@ -127,20 +118,20 @@ const AccordionRoot: Layout = () => "state", "disabled", "ref", - ]); + ); - const selectionMode = () => local.selectionMode ?? "single"; - const variant = () => local.variant ?? "default"; - const hideSeparator = () => Boolean(local.hideSeparator); - const isDisabled = () => Boolean((local.state === "disabled")) || Boolean(local.disabled); + const selectionMode = () => props.selectionMode ?? "single"; + const variant = () => props.variant ?? "default"; + const hideSeparator = () => Boolean(props.hideSeparator); + const isDisabled = () => Boolean((props.state === "disabled")) || Boolean(props.disabled); const [internalValue, setInternalValue] = createSignal( - normalizeAccordionValue(local.defaultValue, selectionMode()), + normalizeAccordionValue(props.defaultValue, selectionMode()), ); const selectedValues = createMemo(() => - local.value !== undefined - ? normalizeAccordionValue(local.value, selectionMode()) + props.value !== undefined + ? normalizeAccordionValue(props.value, selectionMode()) : normalizeAccordionValue(internalValue(), selectionMode()), ); @@ -149,11 +140,11 @@ const AccordionRoot: Layout = () => const setSelectedValues = (nextValues: string[]) => { const normalizedNextValues = normalizeAccordionValue(nextValues, selectionMode()); - if (local.value === undefined) { + if (props.value === undefined) { setInternalValue(normalizedNextValues); } - local.onValueChange?.(normalizedNextValues); + props.onValueChange?.(normalizedNextValues); }; const toggleItem = (value: string) => { @@ -235,38 +226,39 @@ const AccordionRoot: Layout = () => }; return ( - +
{ rootRef = node; - if (typeof local.ref === "function") { - local.ref(node); + if (typeof props.ref === "function") { + props.ref(node); } }} {...{ class: twMerge( CLASSES.Root.base, CLASSES.Root.variant[variant()], - local.class, + props.class, ) }} data-slot="accordion" data-selection-mode={selectionMode()} data-hide-separator={hideSeparator() ? "true" : undefined} data-variant={variant()} data-disabled={isDisabled() ? "true" : "false"} - data-theme={local.dataTheme} - style={local.style} + data-theme={props.dataTheme} + style={props.style} aria-disabled={isDisabled() ? "true" : undefined} > - {local.children} + {props.children}
-
+ ); }; const AccordionItem: Layout = () => { const accordion = useContext(AccordionContext); - const [local, others] = splitProps(props, [ + const others = omit( + props, "value", "children", "class", @@ -274,18 +266,18 @@ const AccordionItem: Layout = () => "style", "state", "disabled", - ]); + ); const uniqueId = createUniqueId(); - const itemValue = () => local.value ?? uniqueId; + const itemValue = () => props.value ?? uniqueId; const triggerId = () => `accordion-trigger-${uniqueId}`; const contentId = () => `accordion-content-${uniqueId}`; const isExpanded = () => accordion?.isItemExpanded(itemValue()) ?? false; const isDisabled = () => - Boolean((local.state === "disabled")) || - Boolean(local.disabled) || + Boolean((props.state === "disabled")) || + Boolean(props.disabled) || Boolean(accordion?.isDisabled()); const toggle = () => { @@ -303,7 +295,7 @@ const AccordionItem: Layout = () => }; return ( - +
= () => isExpanded() && CLASSES.Item.flag.expanded, isDisabled() && CLASSES.Item.flag.disabled, accordion?.hideSeparator() && CLASSES.Item.flag.hideSeparator, - local.class, + props.class, ) }} data-slot="accordion-item" data-expanded={isExpanded() ? "true" : "false"} data-disabled={isDisabled() ? "true" : "false"} - data-theme={local.dataTheme} - style={local.style} + data-theme={props.dataTheme} + style={props.style} > - {local.children} + {props.children}
-
+ ); }; @@ -329,7 +321,8 @@ const AccordionTrigger: Layout = const accordion = useContext(AccordionContext); const item = useContext(AccordionItemContext); - const [local, others] = splitProps(props, [ + const others = omit( + props, "children", "class", "dataTheme", @@ -339,18 +332,18 @@ const AccordionTrigger: Layout = "type", "showIndicator", "indicator", - ]); + ); const isDisabled = () => Boolean(item?.isDisabled()); const handleClick: JSX.EventHandlerUnion = (event) => { - invokeEventHandler(local.onClick, event); + invokeEventHandler(props.onClick, event); if (event.defaultPrevented || isDisabled()) return; item?.toggle(); }; const handleKeyDown: JSX.EventHandlerUnion = (event) => { - invokeEventHandler(local.onKeyDown, event); + invokeEventHandler(props.onKeyDown, event); if (event.defaultPrevented || isDisabled()) return; if (event.key === "Enter" || event.key === " ") { @@ -366,12 +359,12 @@ const AccordionTrigger: Layout = ); @@ -389,16 +382,10 @@ const AccordionTrigger: Layout = const AccordionContent: Layout = () => { const item = useContext(AccordionItemContext); - const [local, others] = splitProps(props, [ - "children", - "class", - "dataTheme", - "style", - "keepMounted", - ]); + const others = omit(props, "children", "class", "dataTheme", "style", "keepMounted"); const expanded = () => Boolean(item?.isExpanded()); - const keepMounted = () => local.keepMounted ?? true; + const keepMounted = () => props.keepMounted ?? true; if (!keepMounted() && !expanded()) { return null; @@ -412,18 +399,18 @@ const AccordionContent: Layout = {...{ class: twMerge( CLASSES.Content.base, expanded() && CLASSES.Content.flag.expanded, - local.class, + props.class, ) }} data-slot="accordion-content" data-expanded={expanded() ? "true" : "false"} - data-theme={local.dataTheme} - style={local.style} + data-theme={props.dataTheme} + style={props.style} aria-hidden={expanded() ? "false" : "true"} aria-labelledby={item?.triggerId()} >
- {local.children} + {props.children}
@@ -432,12 +419,7 @@ const AccordionContent: Layout = const AccordionIndicator: Layout = () => { const item = useContext(AccordionItemContext); - const [local, others] = splitProps(props, [ - "children", - "class", - "dataTheme", - "style", - ]); + const others = omit(props, "children", "class", "dataTheme", "style"); const expanded = () => Boolean(item?.isExpanded()); @@ -448,14 +430,14 @@ const AccordionIndicator: Layout - {local.children ?? ( + {props.children ?? ( , "chi * Avatar Root * -----------------------------------------------------------------------------------------------*/ const AvatarRoot: Layout = () => { - const [local, others] = splitProps(props, [ + const others = omit( + props, "children", "class", "size", @@ -70,12 +62,12 @@ const AvatarRoot: Layout = () => { "variant", "dataTheme", "style", - ]); + ); const [imageLoaded, setImageLoaded] = createSignal(false); - const size = () => local.size ?? "md"; - const flavor = () => local.flavor ?? "neutral"; - const variant = () => local.variant ?? "default"; + const size = () => props.size ?? "md"; + const flavor = () => props.flavor ?? "neutral"; + const variant = () => props.variant ?? "default"; const ctx: AvatarContextValue = { size, @@ -86,22 +78,22 @@ const AvatarRoot: Layout = () => { }; return ( - + - {local.children} + {props.children} - + ); }; @@ -109,36 +101,28 @@ const AvatarRoot: Layout = () => { * Avatar Image * -----------------------------------------------------------------------------------------------*/ const AvatarImage: Layout = () => { - const [local, others] = splitProps(props, [ - "class", - "dataTheme", - "style", - "src", - "alt", - "onLoad", - "onError", - ]); + const others = omit(props, "class", "dataTheme", "style", "src", "alt", "onLoad", "onError"); const ctx = useAvatarContext(); const handleLoad: JSX.EventHandlerUnion = (e) => { ctx.setImageLoaded(true); - if (typeof local.onLoad === "function") local.onLoad(e); + if (typeof props.onLoad === "function") props.onLoad(e); }; const handleError = (e: Event & { currentTarget: HTMLImageElement }) => { ctx.setImageLoaded(false); - if (typeof local.onError === "function") (local.onError as (e: Event) => void)(e); + if (typeof props.onError === "function") (props.onError as (e: Event) => void)(e); }; return ( {local.alt} @@ -149,20 +133,14 @@ const AvatarImage: Layout = () => { * Avatar Fallback * -----------------------------------------------------------------------------------------------*/ const AvatarFallback: Layout = () => { - const [local, others] = splitProps(props, [ - "children", - "class", - "dataTheme", - "style", - "delayMs", - ]); + const others = omit(props, "children", "class", "dataTheme", "style", "delayMs"); const ctx = useAvatarContext(); - const [showFallback, setShowFallback] = createSignal(!local.delayMs); + const [showFallback, setShowFallback] = createSignal(!props.delayMs); - onMount(() => { - if (local.delayMs) { - const timer = setTimeout(() => setShowFallback(true), local.delayMs); + onSettled(() => { + if (props.delayMs) { + const timer = setTimeout(() => setShowFallback(true), props.delayMs); return () => clearTimeout(timer); } }); @@ -174,13 +152,13 @@ const AvatarFallback: Layout = () = {...{ class: twMerge( CLASSES.slot.fallback, (CLASSES.flavor[ctx.flavor() as keyof typeof CLASSES.flavor] ?? `avatar__fallback--flavor-${ctx.flavor()}`), - local.class, + props.class, ) }} data-slot="avatar-fallback" - data-theme={local.dataTheme} - style={local.style} + data-theme={props.dataTheme} + style={props.style} > - {local.children} + {props.children} ); diff --git a/src/components/avatar/AvatarGroup.layout.tsx b/src/components/avatar/AvatarGroup.layout.tsx index 4bb3de06..f832ef08 100644 --- a/src/components/avatar/AvatarGroup.layout.tsx +++ b/src/components/avatar/AvatarGroup.layout.tsx @@ -1,6 +1,6 @@ -import { type JSX, splitProps } from "solid-js"; -import { Dynamic } from "solid-js/web"; -import { twMerge } from "tailwind-merge"; +import {omit} from "solid-js"; +import { Dynamic, type JSX} from "@solidjs/web"; +import { twMerge } from "../../lib/twMerge"; import type { UIBaseProps } from "../vocabulary"; import { CLASSES } from "./Avatar.recipe"; @@ -44,17 +44,19 @@ const VoidElementList: ElementType[] = [ ]; const AvatarGroup: Layout = () => { - const [local, others] = splitProps( + const others = omit( props as AvatarGroupBaseProps & Record, - ["as", "class", "children"], + "as", + "class", + "children", ); - const Tag = local.as || "div"; + const Tag = props.as || "div"; const classes = () => - twMerge(CLASSES.group.base, CLASSES.group.overlap, local.class); + twMerge(CLASSES.group.base, CLASSES.group.overlap, props.class); // Build an aria-label like "Group of N avatar photos" - const ariaLabel = `Group of ${local.children.length} avatar photos`; + const ariaLabel = `Group of ${props.children.length} avatar photos`; if (VoidElementList.includes(Tag)) { return ( @@ -74,7 +76,7 @@ const AvatarGroup: Layout = () => { aria-label={ariaLabel} {...{ class: classes() }} > - {local.children} + {props.children} ); }; diff --git a/src/components/badge/Badge.layout.tsx b/src/components/badge/Badge.layout.tsx index ce4cc69a..f79ae456 100644 --- a/src/components/badge/Badge.layout.tsx +++ b/src/components/badge/Badge.layout.tsx @@ -1,6 +1,7 @@ import { clsx } from "clsx"; -import { type JSX, splitProps } from "solid-js"; -import { twMerge } from "tailwind-merge"; +import type { JSX } from "@solidjs/web"; +import {omit} from "solid-js"; +import { twMerge } from "../../lib/twMerge"; import "./Badge.css"; import { CLASSES } from "./Badge.recipe"; @@ -17,15 +18,15 @@ interface BadgeAnchorProps extends JSX.HTMLAttributes { } const BadgeAnchor: Layout = () => { - const [local, others] = splitProps(props, ["children", "class"]); + const others = omit(props, "children", "class"); return ( - {local.children} + {props.children} ); }; @@ -47,7 +48,8 @@ interface BadgeRootProps extends Omit, "colo } const BadgeRoot: Layout = () => { - const [local, others] = splitProps(props, [ + const others = omit( + props, "children", "class", "flavor", @@ -55,18 +57,18 @@ const BadgeRoot: Layout = () => { "state", "size", "placement", - ]); + ); const classes = () => { - const size = local.size ?? "md"; + const size = props.size ?? "md"; /* Flavor is open, so a name the library does not ship still produces a class an app can style, rather than silently rendering unflavoured. */ - const flavor = local.flavor ?? "neutral"; + const flavor = props.flavor ?? "neutral"; const flavorClass = CLASSES.flavor[flavor as keyof typeof CLASSES.flavor] ?? `badge--flavor-${flavor}`; - const variant = local.variant ?? "solid"; - const state = resolveState(local.state); - const placement = local.placement ?? "top-right"; + const variant = props.variant ?? "solid"; + const state = resolveState(props.state); + const placement = props.placement ?? "top-right"; return twMerge( clsx( @@ -76,13 +78,13 @@ const BadgeRoot: Layout = () => { CLASSES.variant[variant], CLASSES.state[state], CLASSES.placement[placement], - local.class, + props.class, ), ); }; const badgeChildren = () => { - const c = local.children; + const c = props.children; if (typeof c === "string" || typeof c === "number") { return {c}; } @@ -104,15 +106,15 @@ interface BadgeLabelProps extends JSX.HTMLAttributes { } const BadgeLabel: Layout = () => { - const [local, others] = splitProps(props, ["children", "class"]); + const others = omit(props, "children", "class"); return ( - {local.children} + {props.children} ); }; diff --git a/src/components/breadcrumb/Breadcrumb.layout.tsx b/src/components/breadcrumb/Breadcrumb.layout.tsx index 7744f670..9a233707 100644 --- a/src/components/breadcrumb/Breadcrumb.layout.tsx +++ b/src/components/breadcrumb/Breadcrumb.layout.tsx @@ -1,14 +1,7 @@ import "./Breadcrumb.css"; -import { - createContext, - splitProps, - useContext, - Show, - type Component, - type JSX, - type ParentComponent, -} from "solid-js"; -import { twMerge } from "tailwind-merge"; +import type { JSX } from "@solidjs/web"; +import {createContext, omit, useContext, Show, type Component, type ParentComponent} from "solid-js"; +import { twMerge } from "../../lib/twMerge"; import type { UIBaseProps } from "../vocabulary"; import { CLASSES } from "./Breadcrumb.recipe"; import type { Layout } from "../../lib/layouts"; @@ -72,31 +65,25 @@ const ChevronRight = () => ( * Breadcrumb Root * -----------------------------------------------------------------------------------------------*/ const BreadcrumbRoot: Layout = () => { - const [local, others] = splitProps(props, [ - "children", - "class", - "separator", - "dataTheme", - "style", - ]); + const others = omit(props, "children", "class", "separator", "dataTheme", "style"); const ctx: BreadcrumbContextValue = { - separator: () => local.separator, + separator: () => props.separator, }; return ( - + - + ); }; @@ -106,47 +93,40 @@ const BreadcrumbRoot: Layout = () = const [ITEM_CLASS, LINK_CLASS, SEPARATOR_CLASS] = CLASSES.Item.base; const BreadcrumbItem: Layout = () => { - const [local, others] = splitProps(props, [ - "children", - "class", - "href", - "isCurrent", - "dataTheme", - "style", - ]); + const others = omit(props, "children", "class", "href", "isCurrent", "dataTheme", "style"); const ctx = useBreadcrumbContext(); return (
  • - {local.children} + {props.children} } > - {local.children} + {props.children} - + {ctx.separator() ?? } diff --git a/src/components/button-group/ButtonGroup.layout.tsx b/src/components/button-group/ButtonGroup.layout.tsx index c92c93a6..cc250adc 100644 --- a/src/components/button-group/ButtonGroup.layout.tsx +++ b/src/components/button-group/ButtonGroup.layout.tsx @@ -1,6 +1,7 @@ import "./ButtonGroup.css"; -import { splitProps, type Component, type JSX, type ParentComponent } from "solid-js"; -import { twMerge } from "tailwind-merge"; +import type { JSX } from "@solidjs/web"; +import {omit, type Component, type ParentComponent} from "solid-js"; +import { twMerge } from "../../lib/twMerge"; import { CLASSES } from "./ButtonGroup.recipe"; import { ButtonGroupContext } from "./context"; @@ -24,7 +25,8 @@ export type ButtonGroupSeparatorProps = Omit UIBaseProps; const ButtonGroupRoot: Layout = () => { - const [local, others] = splitProps(props, [ + const others = omit( + props, "children", "class", "dataTheme", @@ -35,17 +37,17 @@ const ButtonGroupRoot: Layout = () "state", "fullWidth", "role", - ]); + ); - const orientation = () => local.orientation ?? "horizontal"; + const orientation = () => props.orientation ?? "horizontal"; return ( - local.size, - variant: () => local.variant, - isDisabled: () => (local.state === "disabled"), - fullWidth: () => local.fullWidth, + size: () => props.size, + variant: () => props.variant, + isDisabled: () => (props.state === "disabled"), + fullWidth: () => props.fullWidth, }} >
    = () {...{ class: twMerge( CLASSES.Root.base, CLASSES.Root.orientation[orientation()], - local.fullWidth && CLASSES.Root.flag.fullWidth, - local.class, + props.fullWidth && CLASSES.Root.flag.fullWidth, + props.class, ) }} data-slot="button-group" data-orientation={orientation()} - data-theme={local.dataTheme} - style={local.style} - role={local.role ?? "group"} - aria-disabled={(local.state === "disabled") ? "true" : undefined} + data-theme={props.dataTheme} + style={props.style} + role={props.role ?? "group"} + aria-disabled={(props.state === "disabled") ? "true" : undefined} > - {local.children} + {props.children}
    -
    + ); }; const ButtonGroupSeparator: Layout = () => { - const [local, others] = splitProps(props, ["class", "dataTheme", "style"]); + const others = omit(props, "class", "dataTheme", "style"); return (