Skip to content
1 change: 1 addition & 0 deletions apps/www/src/content/docs/components/dropdown/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Dropdown Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
tag: update
---

import { playground, iconsDemo, customDemo, basicDemo } from "./demo.ts";
Expand Down
71 changes: 49 additions & 22 deletions apps/www/src/content/docs/components/fliter-chip/demo.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
"use client";

export const preview = {
type: "code",
code: `
<Flex direction="column" gap="large" align="center">
<FilterChip
label="Status"
leadingIcon={<Info />}
columnType="select"
import { getPropsString } from "@/lib/utils";

export const getCode = (props: any) => {
const { onRemove, ...rest } = props;
const onRemoveProp = onRemove ? `onRemove={() => alert("Removed")}` : "";

if (props.columnType === "select")
return `
<FilterChip${getPropsString(rest)}
options={[
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" }
]}
/>
<FilterChip
label="Date"
leadingIcon={<Info />}
columnType="date"
/>
<FilterChip
label="Search"
leadingIcon={<Info />}
columnType="text"
/>
</Flex>`,
${onRemoveProp}
/>`;
return `<FilterChip${getPropsString(rest)}${onRemoveProp}/>`;
};

export const playground = {
type: "playground",
controls: {
columnType: {
type: "select",
options: ["select", "date", "string", "number"],
defaultValue: "string",
},
variant: {
type: "select",
options: ["default", "text"],
defaultValue: "default",
},
label: {
type: "text",
initialValue: "Status",
},
leadingIcon: { type: "icon" },
onRemove: {
type: "checkbox",
defaultValue: false,
},
},
getCode,
};

export const inputDemo = {
Expand Down Expand Up @@ -52,12 +70,21 @@ export const inputDemo = {
/>`,
},
{
name: "Text",
name: "String",
code: `
<FilterChip
label="Search"
leadingIcon={<Info />}
columnType="string"
/>`,
},
{
name: "Number",
code: `
<FilterChip
label="Search"
leadingIcon={<Info />}
columnType="text"
columnType="number"
/>`,
},
],
Expand Down
9 changes: 5 additions & 4 deletions apps/www/src/content/docs/components/fliter-chip/index.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
title: FilterChip
description: A compact, interactive element for filtering data with various input types.
tag: update
---

import { preview, inputDemo, iconDemo, actionDemo } from "./demo.ts";
import { playground, inputDemo, iconDemo, actionDemo } from "./demo.ts";

<Demo data={preview} />
<Demo data={playground} />

## Usage

The FilterChip component provides a compact way to filter data with support for different input types like select, date, and text.
The FilterChip component provides a compact way to filter data with support for different input types like select, date, string and number.

```tsx
import { FilterChip } from "@raystack/apsara/v1";
Expand All @@ -34,7 +35,7 @@ import { FilterChip } from "@raystack/apsara/v1";

### Input Types

FilterChip supports three different input types to handle various filtering needs.
FilterChip supports four different input types to handle various filtering needs.

<Demo data={inputDemo} />

Expand Down
11 changes: 9 additions & 2 deletions apps/www/src/content/docs/components/fliter-chip/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ export interface FilterChipProps {
/** Current value of the filter */
value?: string;

/** Type of input for the filter (default: "text") */
columnType?: "select" | "date" | "text";
/** Type of input for the filter
* @default "string"
*/
columnType?: "select" | "date" | "string" | "number";

/** Filterchip variant
* @default "default"
*/
variant?: "default" | "text";

/** Array of options for the select type input */
options?: { label: string; value: string }[];
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";

export const TagSchema = z.enum(["new", "beta", ""]).default("");
export const TagSchema = z.enum(["new", "beta", "update", ""]).default("");

export type TagType = z.infer<typeof TagSchema>;
7 changes: 7 additions & 0 deletions packages/raystack/v1/components/button/button.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
transition: all 0.2s ease-in-out;
}

.button:focus-visible {
outline: 1px solid var(--rs-color-border-accent-emphasis);
}
.button:focus {
outline: none;
}

.button:before,
.button:after {
box-sizing: border-box;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
letter-spacing: var(--rs-letter-spacing-small);
height: 24px;
background: var(--rs-color-background-base-primary);
border: 1px solid var(--rs-color-border-base-tertiary);
border-radius: var(--rs-radius-2);
box-shadow: var(--rs-shadow-feather);
text-wrap: nowrap;
width: fit-content;
}

.chip-default {
border: 1px solid var(--rs-color-border-base-tertiary);
box-shadow: var(--rs-shadow-feather);
}

.chip > * {
padding-left: var(--rs-space-3);
/* padding-right: var(--rs-space-1); */
Expand Down
70 changes: 40 additions & 30 deletions packages/raystack/v1/components/filter-chip/filter-chip.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Cross1Icon } from "@radix-ui/react-icons";
import { ReactElement,ReactNode, useEffect, useState } from "react";

import { ReactElement, ReactNode, useEffect, useState } from "react";

import { Box } from "../box";
import { DatePicker } from "../calendar";
Expand All @@ -16,8 +15,21 @@ import {
FilterType,
FilterTypes,
} from "~/v1/types/filters";
import { cva, VariantProps } from "class-variance-authority";

const chip = cva(styles.chip, {
variants: {
variant: {
default: styles["chip-default"],
text: null,
},
},
defaultVariants: {
variant: "default",
},
});

export interface FilterChipProps {
export interface FilterChipProps extends VariantProps<typeof chip> {
label: string;
value?: string;
onRemove?: () => void;
Expand Down Expand Up @@ -47,7 +59,7 @@ const Operation = ({
const [value, setValue] = useState<string>(filterOptions?.[0]?.value);

useEffect(() => {
const selectedOption = filterOptions.find((o) => o.value === value);
const selectedOption = filterOptions.find(o => o.value === value);
if (selectedOption) {
onOperationSelect(selectedOption);
}
Expand All @@ -57,26 +69,23 @@ const Operation = ({
<Select
value={value}
onValueChange={setValue}
aria-labelledby={`${label}-label`}
>
aria-labelledby={`${label}-label`}>
<Select.Trigger
variant="filter"
variant="text"
className={styles.operation}
aria-label={`${label} filter operation`}
>
aria-label={`${label} filter operation`}>
<Select.Value
placeholder="Select operation"
className={styles.operationText}
/>
</Select.Trigger>
<Select.Content data-variant="filter">
{filterOptions.map((opt) => {
{filterOptions.map(opt => {
return (
<Select.Item
key={opt.value}
value={opt.value}
aria-label={`Filter ${label} ${opt.label}`}
>
aria-label={`Filter ${label} ${opt.label}`}>
{opt.label}
</Select.Item>
);
Expand All @@ -89,19 +98,22 @@ const Operation = ({
export const FilterChip = ({
label,
value,
onRemove = () => null,
onRemove,
className,
ref,
columnType = FilterType.string,
options = [],
onValueChange,
onOperationChange,
leadingIcon,
variant,
...props
}: FilterChipProps) => {
const [operation, setOperation] = useState<FilterOperation>();
const [filterValue, setFilterValue] = useState<any>(value || "");

const showOnRemove = typeof onRemove === "function";

useEffect(() => {
if (onOperationChange && operation?.value) {
onOperationChange(operation?.value);
Expand All @@ -119,15 +131,14 @@ export const FilterChip = ({
case FilterType.select:
return (
<Select value={filterValue.toString()} onValueChange={setFilterValue}>
<Select.Trigger variant="filter" className={styles.selectValue}>
<Select.Trigger variant="text" className={styles.selectValue}>
<Select.Value placeholder="Select value" />
</Select.Trigger>
<Select.Content data-variant="filter">
{options.map((opt) => (
{options.map(opt => (
<Select.Item
key={opt.value.toString()}
value={opt.value.toString()}
>
value={opt.value.toString()}>
{opt.label}
</Select.Item>
))}
Expand All @@ -139,7 +150,7 @@ export const FilterChip = ({
<div className={styles.dateFieldWrapper}>
<DatePicker
value={filterValue}
onSelect={(date) => setFilterValue(date)}
onSelect={date => setFilterValue(date)}
showCalendarIcon={false}
textFieldProps={{ className: styles.dateField }}
/>
Expand All @@ -151,7 +162,7 @@ export const FilterChip = ({
<TextField
className={styles.textField}
value={filterValue}
onChange={(e) => setFilterValue(e.target.value)}
onChange={e => setFilterValue(e.target.value)}
/>
</div>
);
Expand All @@ -161,11 +172,10 @@ export const FilterChip = ({
return (
<Box
ref={ref}
className={[styles.chip, className].filter(Boolean).join(" ")}
className={chip({ variant, className })}
role="group"
aria-label={`Filter by ${label}`}
{...props}
>
{...props}>
<Flex align="center">
<Flex align="center" gap={2}>
{leadingIcon && (
Expand All @@ -183,14 +193,14 @@ export const FilterChip = ({
onOperationSelect={setOperation}
/>
{renderValueInput()}
<div
className={styles.removeIconContainer}
role="button"
tabIndex={0}
aria-label={`Remove ${label} filter`}
>
<Cross1Icon className={styles.removeIcon} onClick={onRemove} />
</div>
{showOnRemove && (
<button
className={styles.removeIconContainer}
aria-label={`Remove ${label} filter`}
onClick={onRemove}>
<Cross1Icon className={styles.removeIcon} />
</button>
)}
</Flex>
</Box>
);
Expand Down
7 changes: 5 additions & 2 deletions packages/raystack/v1/components/select/select.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,12 @@
background-color: var(--rs-color-background-base-primary-hover);
color: var(--rs-color-foreground-base-primary);
}
.trigger:focus-visible {
outline: 1px solid var(--rs-color-border-accent-emphasis);
}

.trigger:focus {
outline: 1px solid var(--rs-color-border-accent-emphasis);
outline: none;
}

.trigger:disabled {
Expand Down Expand Up @@ -259,4 +262,4 @@
[data-disabled=""] {
cursor: not-allowed;
pointer-events: none;
}
}