Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/leptos/src/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::icons::{Location, StarBold};
pub enum Variant {
#[default]
Featured,
Official,
Numeric,
Description,
Location,
Expand Down
10 changes: 9 additions & 1 deletion crates/leptos/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ pub fn Input(
#[prop(into)] disabled: ReadSignal<bool>,
#[prop(into, optional)] class: String,
#[prop(into, optional)] error_message: String,
#[prop(into)] icon: Option<Children>,
#[prop(into, optional)] placeholder: String,
#[prop(into, optional, default = "text".to_string())] r#type: String,
#[prop(into, optional)] name: String,
#[prop(into, optional)] value: String,
#[prop(into, optional)] icon: Option<Children>,
) -> impl IntoView {
let input_class = crate::tw!(
concat!(BASE_CLASS, "-input"),
Expand All @@ -29,6 +33,10 @@ pub fn Input(
<input
class={concat!(BASE_CLASS, "-input__inner")}
disabled=disabled.get()
placeholder=placeholder
name=name
r#type=r#type
value=value
/>
</div>
{has_error.get().then_some(
Expand Down
2 changes: 2 additions & 0 deletions js/react/lib/components/chip/chip.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Location, StarBold } from "@/icons";

export const variants = {
featured: "rustlanges-chip--featured",
official: "rustlanges-chip--official",
numeric: "rustlanges-chip--numeric",
description: "rustlanges-chip--description",
location: "rustlanges-chip--location",
Expand All @@ -12,6 +13,7 @@ export type ChipVariants = keyof typeof variants;

export const icons = {
featured: StarBold,
official: null,
numeric: null,
description: null,
location: Location,
Expand Down
9 changes: 8 additions & 1 deletion js/react/lib/components/chip/chip.showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ registerCase("Chip", {
variant: {
kind: "string",
default: "featured",
options: ["featured", "numeric", "description", "location", "small"],
options: [
"featured",
"official",
"numeric",
"description",
"location",
"small",
],
},
label: {
kind: "string",
Expand Down
157 changes: 80 additions & 77 deletions js/react/lib/components/input-search/input-search.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,94 +4,97 @@ import { Search } from "@/icons/search";
import { cn } from "@/utils/tw-merge";
import { Fragment } from "react/jsx-runtime";
import { Tag } from "../tag";
import { InputHTMLAttributes } from "react";
import { forwardRef, InputHTMLAttributes } from "react";

type Option = { label: string; value: string };
type InputSearchProps = {
filters?: Array<Option>;
activeFilters?: Array<Option>;
onChangeFilter?: (option: Array<Option>) => void;
export type InputSearchOption = { label: string; value: string };
export type InputSearchProps = {
filters?: Array<InputSearchOption>;
activeFilters?: Array<InputSearchOption>;
onChangeFilter?: (option: Array<InputSearchOption>) => void;
} & InputHTMLAttributes<HTMLInputElement>;

export const InputSearch = ({
className,
filters,
activeFilters = [],
onChangeFilter,
...props
}: InputSearchProps) => {
const filterModal = useBoolean();
export const InputSearch = forwardRef<HTMLInputElement, InputSearchProps>(
function InputSearch(
{ className, filters, activeFilters = [], onChangeFilter, ...props },
ref
) {
const filterModal = useBoolean();

const hasFilter = filters?.length;
const hasFilter = filters?.length;

const handleSelectFilter = (filter: Option, isSelected: boolean) => {
if (!isSelected) return onChangeFilter?.([...activeFilters, filter]);
onChangeFilter?.(
activeFilters.filter(({ value }) => value !== filter.value)
);
};
const handleSelectFilter = (
filter: InputSearchOption,
isSelected: boolean
) => {
if (!isSelected) return onChangeFilter?.([...activeFilters, filter]);
onChangeFilter?.(
activeFilters.filter(({ value }) => value !== filter.value)
);
};

const handleCloseOnClickInput = () => hasFilter && filterModal.setFalse();
const handleCloseOnClickInput = () => hasFilter && filterModal.setFalse();

return (
<div className={cn(["rustlanges-input-search-container", className])}>
<label
className={cn([
"rustlanges-input-search",
hasFilter && "rustlanges-input-search--filter",
])}
>
<Search className="" width={24} height={24} />
<input
type="text"
placeholder="Buscar"
onClick={handleCloseOnClickInput}
className="text-caption"
{...props}
/>
</label>
<div className="rustlanges-input-search__filter">
{hasFilter ? (
<Fragment>
<button onClick={filterModal.toggle} tabIndex={0}>
<Filter width={24} height={24} />
</button>
</Fragment>
) : null}
<div
return (
<div className={cn(["rustlanges-input-search-container", className])}>
<label
className={cn([
"rustlanges-input-search-backdrop__content",
filterModal.value
? "rustlanges-input-search-backdrop__content--open"
: "rustlanges-input-search-backdrop__content--closed",
"rustlanges-input-search",
hasFilter && "rustlanges-input-search--filter",
])}
>
{filterModal.value && (
<Search className="" width={24} height={24} />
<input
ref={ref}
type="text"
placeholder="Buscar"
onClick={handleCloseOnClickInput}
className="text-caption"
{...props}
/>
</label>
<div className="rustlanges-input-search__filter">
{hasFilter ? (
<Fragment>
<ul className="rustlanges-input-search-backdrop__list">
{filters?.map(filter => {
const isSelected = activeFilters?.some(
({ value }) => value === filter.value
);
return (
<li
key={filter.value}
onClick={() => handleSelectFilter(filter, isSelected)}
>
<Tag
as="button"
tabIndex={0}
selected={isSelected}
label={filter.label}
/>
</li>
);
})}
</ul>
<button onClick={filterModal.toggle} tabIndex={0}>
<Filter width={24} height={24} />
</button>
</Fragment>
)}
) : null}
<div
className={cn([
"rustlanges-input-search-backdrop__content",
filterModal.value
? "rustlanges-input-search-backdrop__content--open"
: "rustlanges-input-search-backdrop__content--closed",
])}
>
{filterModal.value && (
<Fragment>
<ul className="rustlanges-input-search-backdrop__list">
{filters?.map(filter => {
const isSelected = activeFilters?.some(
({ value }) => value === filter.value
);
return (
<li
key={filter.value}
onClick={() => handleSelectFilter(filter, isSelected)}
>
<Tag
as="button"
tabIndex={0}
selected={isSelected}
label={filter.label}
/>
</li>
);
})}
</ul>
</Fragment>
)}
</div>
</div>
</div>
</div>
);
};
);
}
);
64 changes: 36 additions & 28 deletions js/react/lib/components/input/input.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
import clsx from "clsx";
import { forwardRef } from "react";
import { InputFieldProps } from "./input.types";

export function Input({
errorMessage,
hasError = !!errorMessage,
icon,
disabled,
className,
...props
}: InputFieldProps) {
return (
<div className="rustlanges-input__container">
<div
className={clsx(
"rustlanges-input",
hasError && "rustlanges-input--error",
className
export const Input = forwardRef<HTMLInputElement, InputFieldProps>(
function Input(
{
errorMessage,
hasError = !!errorMessage,
icon,
disabled,
className,
containerClassName,
...props
},
ref
) {
return (
<div className={clsx("rustlanges-input__container", containerClassName)}>
<div
className={clsx(
"rustlanges-input",
hasError && "rustlanges-input--error",
className
)}
>
{icon && <span className="rustlanges-input__icon">{icon}</span>}
<input
ref={ref}
disabled={disabled}
className="rustlanges-input__inner"
{...props}
/>
</div>
{hasError && errorMessage && (
<span className="rustlanges-input__error">{errorMessage}</span>
)}
>
{icon && <span className="rustlanges-input__icon">{icon}</span>}
<input
disabled={disabled}
className="rustlanges-input__inner"
{...props}
/>
</div>
{hasError && errorMessage && (
<span className="rustlanges-input__error">{errorMessage}</span>
)}
</div>
);
}
);
}
);
5 changes: 5 additions & 0 deletions js/react/lib/components/input/input.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ export interface InputFieldProps extends InputHTMLAttributes<HTMLInputElement> {
hasError?: boolean;
errorMessage?: string;
icon?: ReactNode;
/**
* Class applied to the outer container that wraps the input + error message.
* Use `className` to style the input wrapper itself.
*/
containerClassName?: string;
}
6 changes: 5 additions & 1 deletion js/react/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@
"noFallthroughCasesInSwitch": true
},
"include": ["lib"],
"exclude": ["lib/**/*.showcase.tsx", "lib/**/*.showcase.ts", "lib/showcases.ts"]
"exclude": [
"lib/**/*.showcase.tsx",
"lib/**/*.showcase.ts",
"lib/showcases.ts"
]
}
6 changes: 5 additions & 1 deletion js/react/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ export default defineConfig({
// https://rollupjs.org/configuration-options/#input
glob
.sync("lib/**/*.{ts,tsx}", {
ignore: ["lib/**/*.showcase.{ts,tsx}", "lib/**/*.d.ts", "lib/showcases.ts"],
ignore: [
"lib/**/*.showcase.{ts,tsx}",
"lib/**/*.d.ts",
"lib/showcases.ts",
],
})
.map(file => [
// 1. The name of the entry point
Expand Down
48 changes: 48 additions & 0 deletions js/vue/lib/components/dropdown-tree/dropdown-tree.showcase.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script setup lang="ts">
import Showcase from "@rustlanges/showcase/vue";
import RsDropdownTreeStart from "./rs-dropdown-tree-start.vue";
import RsDropdownTreeSubject from "./rs-dropdown-tree-subject.vue";
import RsDropdownTreeTopic from "./rs-dropdown-tree-topic.vue";
import RsDropdownTreeSubTopic from "./rs-dropdown-tree-subtopic.vue";
import RsDropdownTreeEnd from "./rs-dropdown-tree-end.vue";
</script>

<template>
<Showcase name="DropdownTree">
<RsDropdownTreeStart
variant="default"
level="n1"
state="completed"
title="Introducción a Rust"
>
<RsDropdownTreeSubject
level="n1"
state="completed"
title="Título del tema"
name="subject"
value="a"
>
<RsDropdownTreeTopic level="n1" state="reading" title="Tópico">
<RsDropdownTreeSubTopic
level="n1"
state="completed"
title="Subtópico"
/>
<RsDropdownTreeSubTopic
level="n1"
state="reading"
title="Subtópico"
/>
<RsDropdownTreeSubTopic
level="n1"
state="pending"
title="Subtópico"
/>
</RsDropdownTreeTopic>
<RsDropdownTreeEnd title="Continúa aprendiendo">
Conoce todos nuestros proyectos Open Source.
</RsDropdownTreeEnd>
</RsDropdownTreeSubject>
</RsDropdownTreeStart>
</Showcase>
</template>
5 changes: 5 additions & 0 deletions js/vue/lib/components/dropdown-tree/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as RsDropdownTreeStart } from "./rs-dropdown-tree-start.vue";
export { default as RsDropdownTreeSubject } from "./rs-dropdown-tree-subject.vue";
export { default as RsDropdownTreeTopic } from "./rs-dropdown-tree-topic.vue";
export { default as RsDropdownTreeSubTopic } from "./rs-dropdown-tree-subtopic.vue";
export { default as RsDropdownTreeEnd } from "./rs-dropdown-tree-end.vue";
Loading
Loading