diff --git a/packages/kit/package.json b/packages/kit/package.json
index 063c8e2..891cdfd 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -55,39 +55,39 @@
},
"devDependencies": {
"@codeui/vanilla-extract": "workspace:*",
- "@testing-library/jest-dom": "^5.16.5",
- "jest": "^28.1.3",
- "jest-environment-jsdom": "^28.1.3",
- "rollup": "^3.20.2",
+ "@testing-library/jest-dom": "^5.17.0",
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^29.7.0",
+ "rollup": "^4.15.0",
"rollup-preset-solid": "^2.0.1",
- "solid-js": "^1.7.3",
- "solid-testing-library": "^0.3.0",
- "ts-node": "^10.9.1",
- "typescript": "^4.9.5",
- "vite-tsconfig-paths": "^4.0.7"
+ "solid-js": "^1.8.16",
+ "solid-testing-library": "^0.5.1",
+ "ts-node": "^10.9.2",
+ "typescript": "^5.4.5",
+ "vite-tsconfig-paths": "^4.3.2"
},
"peerDependencies": {
"solid-js": "^1.7.0"
},
"packageManager": "pnpm@7.5.0",
"dependencies": {
- "@kobalte/core": "^0.11.0",
+ "@kobalte/core": "^0.12.6",
"@kobalte/utils": "^0.9.0",
- "@kobalte/vanilla-extract": "^0.4.0",
- "@maskito/core": "^1.9.0",
- "@maskito/kit": "^1.9.0",
+ "@kobalte/vanilla-extract": "^0.5.0",
+ "@maskito/core": "^2.3.0",
+ "@maskito/kit": "^2.3.0",
"@motionone/solid": "^10.16.0",
"@radix-ui/colors": "^0.1.8",
- "@solid-primitives/pagination": "^0.2.5",
- "@solid-primitives/scheduled": "^1.4.1",
- "@tanstack/solid-virtual": "^3.0.0-beta.6",
- "@tanstack/virtual-core": "^3.0.0-alpha.1",
- "@vanilla-extract/css": "^1.11.0",
- "@vanilla-extract/dynamic": "^2.0.3",
- "@vanilla-extract/recipes": "^0.4.0",
- "@vanilla-extract/vite-plugin": "^3.8.0",
- "motion": "^10.15.5",
- "polished": "^4.2.2",
- "statebuilder": "^0.3.1"
+ "@solid-primitives/pagination": "^0.3.0",
+ "@solid-primitives/scheduled": "^1.4.3",
+ "@tanstack/solid-virtual": "^3.4.0",
+ "@tanstack/virtual-core": "^3.4.0",
+ "@vanilla-extract/css": "^1.14.2",
+ "@vanilla-extract/dynamic": "^2.1.0",
+ "@vanilla-extract/recipes": "^0.5.2",
+ "@vanilla-extract/vite-plugin": "^4.0.7",
+ "motion": "^10.17.0",
+ "polished": "^4.3.1",
+ "statebuilder": "^0.6.0"
}
}
diff --git a/packages/kit/src/components/Combobox/Combobox.css.ts b/packages/kit/src/components/Combobox/Combobox.css.ts
new file mode 100644
index 0000000..e755aee
--- /dev/null
+++ b/packages/kit/src/components/Combobox/Combobox.css.ts
@@ -0,0 +1,211 @@
+import { createTheme, keyframes, style } from "@vanilla-extract/css";
+import { themeTokens } from "../../foundation/themes.css";
+import { componentStateStyles } from "@kobalte/vanilla-extract";
+import { tokens } from "../../foundation/contract.css";
+import { baseFieldTheme, baseFieldVars } from "../Field/Field.css";
+import { responsiveStyle } from "../../foundation/responsive";
+import { themeVars } from "../../foundation";
+
+export const [selectTheme, selectThemeVars] = createTheme({
+ contentBackground: tokens.dropdownBackground,
+ contentRadius: themeTokens.radii.lg,
+ contentBoxShadow: tokens.dropdownBoxShadow,
+ contentPadding: themeTokens.spacing["2"],
+ contentBorderColor: tokens.dropdownBorder,
+ contentMaxHeight: "400px",
+ contentMaxHeightXs: "270px",
+ separator: tokens.dropdownBorder,
+ itemMinHeight: "2.60rem",
+ itemTextColor: tokens.dropdownItemTextColor,
+ itemHoverBackground: tokens.dropdownItemHoverBackground,
+ itemHoverTextColor: tokens.dropdownItemHoverTextColor,
+ itemDisabledOpacity: ".4",
+ indicatorSize: "20px",
+});
+
+const contentShow = keyframes({
+ from: {
+ opacity: 0,
+ transform: "translateY(-10px)",
+ },
+ to: {
+ opacity: 1,
+ transform: "translateY(0px)",
+ },
+});
+
+const contentHide = keyframes({
+ from: {
+ opacity: 1,
+ transform: "translateY(0px)",
+ },
+ to: {
+ opacity: 0,
+ transform: "translateY(-10px)",
+ },
+});
+
+// TODO: common popover/dropdown style
+export const content = style([
+ selectTheme,
+ {
+ boxShadow: selectThemeVars.contentBoxShadow,
+ backgroundColor: selectThemeVars.contentBackground,
+ borderRadius: selectThemeVars.contentRadius,
+ padding: selectThemeVars.contentPadding,
+ overflow: "auto",
+ zIndex: themeTokens.zIndex["50"],
+ listStyleType: "none",
+ display: "flex",
+ flexDirection: "column",
+ rowGap: themeTokens.spacing["1"],
+ outline: "none",
+ maxHeight: selectThemeVars.contentMaxHeight,
+ animation: `${contentHide} 250ms ease-in-out`,
+ border: `1px solid ${selectThemeVars.contentBorderColor}`,
+ },
+ responsiveStyle({
+ xs: {
+ vars: {
+ [selectThemeVars.contentMaxHeight]: selectThemeVars.contentMaxHeightXs,
+ },
+ },
+ sm: {
+ vars: {
+ [selectThemeVars.contentMaxHeight]: "400px",
+ },
+ },
+ }),
+ componentStateStyles({
+ expanded: {
+ animation: `${contentShow} 250ms ease-in-out`,
+ },
+ }),
+]);
+
+export const input = style([
+ {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ },
+]);
+
+export const item = style([
+ {
+ textAlign: "left",
+ justifyContent: "space-between",
+ border: 0,
+ padding: `${themeTokens.spacing["2"]} ${themeTokens.spacing["3"]}`,
+ borderRadius: themeTokens.radii.sm,
+ background: "transparent",
+ color: selectThemeVars.itemTextColor,
+ userSelect: "none",
+ display: "flex",
+ alignItems: "center",
+ outline: "none",
+ fontWeight: themeTokens.fontWeight.normal,
+ transition: "opacity .2s, background-color .2s, transform .2s",
+ gap: themeTokens.spacing["2"],
+ margin: `${themeTokens.spacing["1"]} 0`,
+ minHeight: selectThemeVars.itemMinHeight,
+ selectors: {
+ "&:first-child,&:last-child": {
+ margin: 0,
+ },
+ },
+ },
+ {
+ ":disabled": {
+ opacity: selectThemeVars.itemDisabledOpacity,
+ },
+ ":focus": {
+ boxShadow: "none",
+ outline: "none",
+ backgroundColor: selectThemeVars.itemHoverBackground,
+ color: selectThemeVars.itemHoverTextColor,
+ },
+ ":focus-visible": {
+ backgroundColor: selectThemeVars.itemHoverBackground,
+ color: selectThemeVars.itemHoverTextColor,
+ },
+ },
+ componentStateStyles({
+ highlighted: {
+ boxShadow: "none",
+ outline: "none",
+ backgroundColor: selectThemeVars.itemHoverBackground,
+ color: selectThemeVars.itemHoverTextColor,
+ },
+ selected: {
+ not: {
+ paddingRight: `calc(${themeTokens.spacing["3"]} + ${selectThemeVars.indicatorSize} + ${themeTokens.spacing["2"]})`,
+ },
+ },
+ disabled: {
+ opacity: selectThemeVars.itemDisabledOpacity,
+ not: {
+ ":hover": {},
+ },
+ },
+ }),
+]);
+
+export const field = style([
+ baseFieldTheme,
+ {
+ display: "flex",
+ flexDirection: "column",
+ gap: themeTokens.spacing["3"],
+ flex: 1,
+ height: "100%",
+ },
+]);
+
+// TODO: Unify with Select?
+export const comboboxField = style([
+ {
+ display: "inline-flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ paddingRight: themeTokens.spacing["3"],
+ paddingLeft: themeTokens.spacing["3"],
+ paddingTop: 0,
+ paddingBottom: 0,
+ outline: "none",
+ width: "100%",
+ fontSize: baseFieldVars.fontSize,
+ },
+]);
+
+export const comboboxInput = style({
+ color: themeVars.foreground,
+ appearance: "none",
+ background: "transparent",
+ outline: "none",
+ border: 0,
+ display: "inline-flex",
+ minWidth: 0,
+ width: "100%",
+});
+
+export const comboboxTrigger = style({
+ border: 0,
+ background: "transparent",
+ outline: "none",
+ padding: 0,
+ color: themeVars.foreground,
+});
+
+export const itemIndicator = style({
+ marginLeft: "auto",
+ height: selectThemeVars.indicatorSize,
+ width: selectThemeVars.indicatorSize,
+ flexShrink: 0,
+});
+
+export const comboboxInputWorkaround = style({
+ width: 0,
+ height: 0,
+ opacity: 0,
+});
diff --git a/packages/kit/src/components/Combobox/Combobox.tsx b/packages/kit/src/components/Combobox/Combobox.tsx
new file mode 100644
index 0000000..8891a3a
--- /dev/null
+++ b/packages/kit/src/components/Combobox/Combobox.tsx
@@ -0,0 +1,186 @@
+import { Combobox as KCombobox, createControllableBooleanSignal } from "@kobalte/core";
+import { Accessor, JSX, JSXElement, Show, createSignal, splitProps } from "solid-js";
+import { CheckIcon } from "../../icons/CheckIcon";
+import { SelectorIcon } from "../../icons/SelectorIcon";
+import { mergeClasses } from "../../utils/css";
+import { highlight } from "../../utils/highlight/highlight";
+import {
+ FieldWithErrorMessageSupport,
+ createFieldErrorMessageProps,
+} from "../Field/FieldError/createFieldErrorMessageProps";
+import { createFieldLabelProps } from "../Field/FieldLabel/createFieldLabelProps";
+import { createFieldMessageProps } from "../Field/FieldMessage/createFieldMessageProps";
+import { BaseFieldProps, createBaseFieldProps } from "../Field/createBaseFieldProps";
+import * as styles from "./Combobox.css";
+
+void highlight;
+
+export type ComboboxProps