parent
5a6193d365
commit
3c60d33a6c
@ -0,0 +1,32 @@
|
|||||||
|
// SearchField — eidos compound API, disciplined option C.
|
||||||
|
//
|
||||||
|
// import { SearchField } from '$uix/eidos/components/search-field';
|
||||||
|
//
|
||||||
|
// <SearchField bind:value>
|
||||||
|
// <SearchField.Input />
|
||||||
|
// <SearchField.ClearTrigger>Clear</SearchField.ClearTrigger>
|
||||||
|
// </SearchField>
|
||||||
|
import SearchFieldRoot from './search-field.svelte';
|
||||||
|
import Input from './search-field-input.svelte';
|
||||||
|
import ClearTrigger from './search-field-clear-trigger.svelte';
|
||||||
|
|
||||||
|
type SearchFieldNamespace = typeof SearchFieldRoot & {
|
||||||
|
Input: typeof Input;
|
||||||
|
ClearTrigger: typeof ClearTrigger;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SearchField = SearchFieldRoot as SearchFieldNamespace;
|
||||||
|
SearchField.Input = Input;
|
||||||
|
SearchField.ClearTrigger = ClearTrigger;
|
||||||
|
|
||||||
|
export { SearchField };
|
||||||
|
|
||||||
|
export default SearchField;
|
||||||
|
|
||||||
|
export type {
|
||||||
|
SearchFieldProps,
|
||||||
|
SearchFieldInputProps as InputProps,
|
||||||
|
SearchFieldClearTriggerProps as ClearTriggerProps,
|
||||||
|
SearchFieldProviderSnippetProps as ProviderSnippetProps,
|
||||||
|
SearchFieldSize
|
||||||
|
} from './types';
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { ClearTrigger as SomaSearchFieldClearTrigger } from '$soma/components/search-field';
|
||||||
|
import type { SearchFieldClearTriggerProps } from './types';
|
||||||
|
|
||||||
|
let { children, ...rest }: SearchFieldClearTriggerProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SomaSearchFieldClearTrigger {...rest}>
|
||||||
|
{@render children?.()}
|
||||||
|
</SomaSearchFieldClearTrigger>
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Input as SomaSearchFieldInput } from '$soma/components/search-field';
|
||||||
|
import type { SearchFieldInputProps } from './types';
|
||||||
|
|
||||||
|
let { children, ...rest }: SearchFieldInputProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SomaSearchFieldInput {...rest}>
|
||||||
|
{@render children?.()}
|
||||||
|
</SomaSearchFieldInput>
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
[data-search-field] {
|
||||||
|
--_search-field-height: var(--search-field-height-md);
|
||||||
|
--_search-field-px: var(--search-field-px-md);
|
||||||
|
--_search-field-gap: var(--search-field-gap-md);
|
||||||
|
--_search-field-font-size: var(--search-field-font-size-md);
|
||||||
|
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--_search-field-gap);
|
||||||
|
inline-size: 100%;
|
||||||
|
min-inline-size: 0;
|
||||||
|
block-size: var(--_search-field-height);
|
||||||
|
padding-inline: var(--_search-field-px);
|
||||||
|
border: var(--search-field-border-width) solid var(--search-field-border);
|
||||||
|
border-radius: var(--search-field-radius);
|
||||||
|
background: var(--search-field-bg);
|
||||||
|
color: var(--search-field-color);
|
||||||
|
font-family: var(--search-field-font-family);
|
||||||
|
font-size: var(--_search-field-font-size);
|
||||||
|
line-height: var(--search-field-line-height);
|
||||||
|
transition:
|
||||||
|
background var(--search-field-transition-duration) var(--search-field-transition-ease),
|
||||||
|
border-color var(--search-field-transition-duration) var(--search-field-transition-ease),
|
||||||
|
box-shadow var(--search-field-transition-duration) var(--search-field-transition-ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field][data-size='sm'] {
|
||||||
|
--_search-field-height: var(--search-field-height-sm);
|
||||||
|
--_search-field-px: var(--search-field-px-sm);
|
||||||
|
--_search-field-gap: var(--search-field-gap-sm);
|
||||||
|
--_search-field-font-size: var(--search-field-font-size-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field][data-size='lg'] {
|
||||||
|
--_search-field-height: var(--search-field-height-lg);
|
||||||
|
--_search-field-px: var(--search-field-px-lg);
|
||||||
|
--_search-field-gap: var(--search-field-gap-lg);
|
||||||
|
--_search-field-font-size: var(--search-field-font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field][data-focused] {
|
||||||
|
border-color: var(--search-field-border-focus);
|
||||||
|
box-shadow: var(--search-field-focus-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field][data-invalid] {
|
||||||
|
border-color: var(--search-field-border-invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field][data-disabled] {
|
||||||
|
opacity: var(--search-field-disabled-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-input] {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-inline-size: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-input]::placeholder {
|
||||||
|
color: var(--search-field-placeholder-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-input][data-disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-clear-trigger] {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: var(--search-field-clear-size);
|
||||||
|
block-size: var(--search-field-clear-size);
|
||||||
|
border: var(--search-field-clear-border-width) solid var(--search-field-clear-border);
|
||||||
|
border-radius: var(--search-field-clear-radius);
|
||||||
|
background: var(--search-field-clear-bg);
|
||||||
|
color: var(--search-field-clear-color);
|
||||||
|
font: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
transition:
|
||||||
|
background var(--search-field-transition-duration) var(--search-field-transition-ease),
|
||||||
|
border-color var(--search-field-transition-duration) var(--search-field-transition-ease),
|
||||||
|
color var(--search-field-transition-duration) var(--search-field-transition-ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-clear-trigger]:hover:not([data-disabled]) {
|
||||||
|
border-color: var(--search-field-clear-border-hover);
|
||||||
|
background: var(--search-field-clear-bg-hover);
|
||||||
|
color: var(--search-field-clear-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-clear-trigger]:focus-visible {
|
||||||
|
box-shadow: var(--search-field-clear-focus-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-search-field-clear-trigger][data-disabled],
|
||||||
|
[data-search-field][data-empty] [data-search-field-clear-trigger] {
|
||||||
|
cursor: default;
|
||||||
|
opacity: var(--search-field-clear-hidden-opacity);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
[data-search-field],
|
||||||
|
[data-search-field-clear-trigger] {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
/**
|
||||||
|
* Eidos `<SearchField>` — visual wrapper over Soma's search primitive.
|
||||||
|
* Soma owns value, clear and submit behavior; Eidos adds `size`.
|
||||||
|
*/
|
||||||
|
import { ActiveEidos } from '$uix/eidos';
|
||||||
|
import { Provider as SomaSearchFieldProvider } from '$soma/components/search-field';
|
||||||
|
import type { SearchFieldProps } from './types';
|
||||||
|
|
||||||
|
let { size = 'md', value = $bindable(''), children, ...rest }: SearchFieldProps = $props();
|
||||||
|
|
||||||
|
const eidos = ActiveEidos.require();
|
||||||
|
const resolvedSize = $derived(eidos.resolve(size, 'md'));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SomaSearchFieldProvider {...rest} bind:value data-size={resolvedSize}>
|
||||||
|
{#snippet children(snippetProps)}
|
||||||
|
{@render children?.(snippetProps)}
|
||||||
|
{/snippet}
|
||||||
|
</SomaSearchFieldProvider>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import type {
|
||||||
|
ClearTriggerProps as SomaSearchFieldClearTriggerProps,
|
||||||
|
InputProps as SomaSearchFieldInputProps,
|
||||||
|
ProviderProps as SomaSearchFieldProviderProps,
|
||||||
|
ProviderSnippetProps as SearchFieldProviderSnippetProps
|
||||||
|
} from '$soma/components/search-field';
|
||||||
|
import type { ResponsiveProp, Size } from '$uix/eidos/lib/types';
|
||||||
|
|
||||||
|
export type SearchFieldSize = Extract<Size, 'sm' | 'md' | 'lg'>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for the eidos `<SearchField>`.
|
||||||
|
*
|
||||||
|
* Extends Soma's search field with visual sizing only. Value, focus, clear,
|
||||||
|
* submit and integrated Field state are owned by Soma.
|
||||||
|
*/
|
||||||
|
export type SearchFieldProps = SomaSearchFieldProviderProps & {
|
||||||
|
/** Visual size. Accepts a responsive map resolved by ActiveEidos. @default 'md' */
|
||||||
|
size?: ResponsiveProp<SearchFieldSize>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SearchFieldInputProps = SomaSearchFieldInputProps;
|
||||||
|
export type SearchFieldClearTriggerProps = SomaSearchFieldClearTriggerProps;
|
||||||
|
export type { SearchFieldProviderSnippetProps };
|
||||||
Loading…
Reference in new issue