@flightlesslabs/dodo-ui 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/index.d.ts +4 -1
  2. package/dist/index.js +2 -0
  3. package/dist/stories/components/Form/DatePicker/DatePicker.svelte +1 -0
  4. package/dist/stories/components/Form/NumericInput/NumericInput.svelte +1 -0
  5. package/dist/stories/components/Form/PasswordInput/PasswordInput.svelte +1 -0
  6. package/dist/stories/components/Form/Search/Events/Events.stories.svelte +137 -0
  7. package/dist/stories/components/Form/Search/Events/Events.stories.svelte.d.ts +18 -0
  8. package/dist/stories/components/Form/Search/Roundness/Roundness.stories.svelte +21 -0
  9. package/dist/stories/components/Form/Search/Roundness/Roundness.stories.svelte.d.ts +26 -0
  10. package/dist/stories/components/Form/Search/Search.stories.svelte +40 -0
  11. package/dist/stories/components/Form/Search/Search.stories.svelte.d.ts +21 -0
  12. package/dist/stories/components/Form/Search/Search.svelte +142 -0
  13. package/dist/stories/components/Form/Search/Search.svelte.d.ts +66 -0
  14. package/dist/stories/components/Form/Search/SearchIcon/SearchIcon.stories.svelte +27 -0
  15. package/dist/stories/components/Form/Search/SearchIcon/SearchIcon.stories.svelte.d.ts +26 -0
  16. package/dist/stories/components/Form/Search/Size/Size.stories.svelte +17 -0
  17. package/dist/stories/components/Form/Search/Size/Size.stories.svelte.d.ts +26 -0
  18. package/dist/stories/components/Form/Search/WithIcon/WithIcon.stories.svelte +47 -0
  19. package/dist/stories/components/Form/Search/WithIcon/WithIcon.stories.svelte.d.ts +26 -0
  20. package/dist/stories/components/Form/Select/Select.svelte +1 -0
  21. package/dist/stories/components/Form/Select/Select.svelte.d.ts +4 -4
  22. package/dist/stories/components/Form/TextInput/TextInput.svelte +1 -0
  23. package/dist/stories/components/Layout/Accordian/Accordian.svelte.d.ts +2 -2
  24. package/dist/stories/developer tools/components/UtilityIcon/Size/Size.stories.svelte +25 -0
  25. package/dist/stories/developer tools/components/UtilityIcon/Size/Size.stories.svelte.d.ts +26 -0
  26. package/dist/stories/developer tools/components/UtilityIcon/UtilityIcon.stories.svelte +26 -0
  27. package/dist/stories/developer tools/components/UtilityIcon/UtilityIcon.stories.svelte.d.ts +21 -0
  28. package/dist/stories/developer tools/components/UtilityIcon/UtilityIcon.svelte +58 -0
  29. package/dist/stories/developer tools/components/UtilityIcon/UtilityIcon.svelte.d.ts +19 -0
  30. package/dist/types/special.d.ts +1 -1
  31. package/package.json +9 -9
  32. package/src/lib/index.ts +5 -1
  33. package/src/lib/stories/components/Form/DatePicker/DatePicker.svelte +1 -0
  34. package/src/lib/stories/components/Form/NumericInput/NumericInput.svelte +1 -0
  35. package/src/lib/stories/components/Form/PasswordInput/PasswordInput.svelte +1 -0
  36. package/src/lib/stories/components/Form/Search/Search.svelte +285 -0
  37. package/src/lib/stories/components/Form/Select/Select.svelte +5 -4
  38. package/src/lib/stories/components/Form/TextInput/TextInput.svelte +1 -0
  39. package/src/lib/stories/components/Layout/Accordian/Accordian.svelte +2 -2
  40. package/src/lib/stories/developer tools/components/UtilityIcon/UtilityIcon.svelte +90 -0
  41. package/src/lib/types/special.ts +1 -1
@@ -0,0 +1,26 @@
1
+ export default WithIcon;
2
+ type WithIcon = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const WithIcon: $$__sveltets_2_IsomorphicComponent<{
10
+ [x: string]: never;
11
+ }, {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}, {}, string>;
14
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
+ $$bindings?: Bindings;
17
+ } & Exports;
18
+ (internal: unknown, props: {
19
+ $$events?: Events;
20
+ $$slots?: Slots;
21
+ }): Exports & {
22
+ $set?: any;
23
+ $on?: any;
24
+ };
25
+ z_$$bindings?: Bindings;
26
+ }
@@ -176,6 +176,7 @@ function onKeyBoardEnter(e, selectedItemIndex) {
176
176
  value={searchable ? searchTerm : selectedOption?.label}
177
177
  {readonly}
178
178
  variant={searchable ? 'input' : 'button'}
179
+ {size}
179
180
  >
180
181
  {#snippet customInputContent()}
181
182
  {#if customInputContentTyped}
@@ -70,11 +70,11 @@ export interface SelectProps {
70
70
  onkeyup?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
71
71
  /** custom Content Formatting for variant button */
72
72
  customInputContent?: (val: SelectOption) => Snippet;
73
- /** custom Content Formatting for variant button */
73
+ /** custom Menu Item Content */
74
74
  customMenuItemContent?: (val: SelectOption, selected: boolean) => Snippet;
75
75
  /** Custom Popup Content */
76
76
  customPopupContent?: (options: SelectOption[], selectedOption: SelectOption, onselect: (val: SelectOption) => void) => Snippet;
77
- /** custom Content Formatting for variant button */
77
+ /** custom Placeholder MenuItem Content */
78
78
  customPlaceholderMenuItemContent?: () => Snippet;
79
79
  /** PopperPopup Max height. Use css compatible value */
80
80
  popupMaxHeight?: string;
@@ -89,7 +89,7 @@ export interface SelectProps {
89
89
  /** Dropdown Arrow Icon */
90
90
  customDropdownArrowIcon?: (open: boolean) => Snippet;
91
91
  /** Select Dropdown Arrow Position */
92
- dropdownArrowPosition?: DropdownArrowPosition;
92
+ dropdownArrowPosition?: IconPosition;
93
93
  /** Popup stick horizontally */
94
94
  popupPositionX?: PositionX;
95
95
  /** Popup stick vertically */
@@ -102,7 +102,7 @@ export interface SelectProps {
102
102
  open?: boolean;
103
103
  }
104
104
  import { type MenuItemProps, type MenuProps, type PaperProps, type PopperProps, type PositionX, type PositionY } from '../../../../index.js';
105
- import type { DropdownArrowPosition } from '../../../../types/special.js';
105
+ import type { IconPosition } from '../../../../types/special.js';
106
106
  declare const Select: import("svelte").Component<SelectProps, {}, "ref" | "open">;
107
107
  type Select = ReturnType<typeof Select>;
108
108
  export default Select;
@@ -39,6 +39,7 @@ function onblurMod(e) {
39
39
  {name}
40
40
  {id}
41
41
  {disabled}
42
+ {size}
42
43
  bind:ref
43
44
  bind:focused
44
45
  {oninput}
@@ -1,5 +1,5 @@
1
1
  import type { ComponentSize } from '../../../../types/size.js';
2
- import type { DropdownArrowPosition } from '../../../../types/special.js';
2
+ import type { IconPosition } from '../../../../types/special.js';
3
3
  import { type Snippet } from 'svelte';
4
4
  import type { EventHandler } from 'svelte/elements';
5
5
  export type AccordianToggleEvent = Event & {
@@ -25,7 +25,7 @@ export interface AccordianProps {
25
25
  /** How large should the button be? */
26
26
  size?: ComponentSize;
27
27
  /** Select Dropdown Arrow Position */
28
- dropdownArrowPosition?: DropdownArrowPosition;
28
+ dropdownArrowPosition?: IconPosition;
29
29
  /** Dropdown Arrow Icon */
30
30
  customDropdownArrowIcon?: (open: boolean) => Snippet;
31
31
  }
@@ -0,0 +1,25 @@
1
+ <script module>
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import UtilityIcon from '../UtilityIcon.svelte';
4
+ import { storyUtilityIconArgTypes } from '../UtilityIcon.stories.svelte';
5
+ import Icon from '@iconify/svelte';
6
+
7
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
8
+ const { Story } = defineMeta({
9
+ component: UtilityIcon,
10
+ tags: ['autodocs'],
11
+ argTypes: storyUtilityIconArgTypes,
12
+ });
13
+ </script>
14
+
15
+ <Story name="Normal">
16
+ <Icon icon="mdi:eye" width="24" height="24" />
17
+ </Story>
18
+
19
+ <Story name="Small" args={{ size: 'small' }}>
20
+ <Icon icon="mdi:eye" width="24" height="24" />
21
+ </Story>
22
+
23
+ <Story name="Large" args={{ size: 'large' }}>
24
+ <Icon icon="mdi:eye" width="24" height="24" />
25
+ </Story>
@@ -0,0 +1,26 @@
1
+ export default Size;
2
+ type Size = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const Size: $$__sveltets_2_IsomorphicComponent<{
10
+ [x: string]: never;
11
+ }, {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}, {}, string>;
14
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
+ $$bindings?: Bindings;
17
+ } & Exports;
18
+ (internal: unknown, props: {
19
+ $$events?: Events;
20
+ $$slots?: Slots;
21
+ }): Exports & {
22
+ $set?: any;
23
+ $on?: any;
24
+ };
25
+ z_$$bindings?: Bindings;
26
+ }
@@ -0,0 +1,26 @@
1
+ <script module lang="ts">import { defineMeta } from '@storybook/addon-svelte-csf';
2
+ import UtilityIcon from './UtilityIcon.svelte';
3
+ import Icon from '@iconify/svelte';
4
+ import { componentSizeArray } from '../../../../types/size.js';
5
+ export const storyUtilityIconArgTypes = {
6
+ size: {
7
+ control: { type: 'select' },
8
+ options: componentSizeArray,
9
+ },
10
+ };
11
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
12
+ const { Story } = defineMeta({
13
+ component: UtilityIcon,
14
+ tags: ['autodocs'],
15
+ argTypes: storyUtilityIconArgTypes,
16
+ });
17
+ </script>
18
+
19
+ <!-- Button with default style -->
20
+ <Story name="Default">
21
+ <Icon icon="mdi:eye" width="24" height="24" />
22
+ </Story>
23
+
24
+ <Story name="Disabled" args={{ disabled: true }}>
25
+ <Icon icon="mdi:eye" width="24" height="24" />
26
+ </Story>
@@ -0,0 +1,21 @@
1
+ import UtilityIcon from './UtilityIcon.svelte';
2
+ import type { StoryBookArgTypes } from '../../../../storybook-types.js';
3
+ export declare const storyUtilityIconArgTypes: StoryBookArgTypes;
4
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
5
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
+ $$bindings?: Bindings;
7
+ } & Exports;
8
+ (internal: unknown, props: {
9
+ $$events?: Events;
10
+ $$slots?: Slots;
11
+ }): Exports & {
12
+ $set?: any;
13
+ $on?: any;
14
+ };
15
+ z_$$bindings?: Bindings;
16
+ }
17
+ declare const UtilityIcon: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
18
+ [evt: string]: CustomEvent<any>;
19
+ }, {}, {}, string>;
20
+ type UtilityIcon = InstanceType<typeof UtilityIcon>;
21
+ export default UtilityIcon;
@@ -0,0 +1,58 @@
1
+ <script lang="ts" module>export {};
2
+ </script>
3
+
4
+ <script lang="ts">"use strict";
5
+ let { children, size = 'normal', id, class: className = '', disabled = false, ref = $bindable(), } = $props();
6
+ </script>
7
+
8
+ <span
9
+ class={['dodo-ui-UtilityIcon', `size--${size}`, className].join(' ')}
10
+ class:disabled
11
+ {id}
12
+ bind:this={ref}
13
+ >
14
+ {#if children}
15
+ {@render children()}
16
+ {/if}
17
+ </span>
18
+
19
+ <style>:global(:root) {
20
+ --dodo-ui-UtilityIcon-disabled-color: var(--dodo-color-neutral-400);
21
+ }
22
+
23
+ :global(.dodo-theme--dark) {
24
+ --dodo-ui-UtilityIcon-disabled-color: var(--dodo-color-neutral-500);
25
+ }
26
+
27
+ .dodo-ui-UtilityIcon {
28
+ outline: none;
29
+ transition: all 150ms;
30
+ text-decoration: none;
31
+ margin: 0;
32
+ display: inline-flex;
33
+ justify-content: center;
34
+ align-items: center;
35
+ font-family: inherit;
36
+ background-color: transparent;
37
+ color: var(--dodo-color-neutral-600);
38
+ font-family: inherit;
39
+ }
40
+ .dodo-ui-UtilityIcon.size--normal {
41
+ height: var(--dodo-ui-element-height-normal);
42
+ width: var(--dodo-ui-element-height-normal);
43
+ font-size: 1rem;
44
+ }
45
+ .dodo-ui-UtilityIcon.size--small {
46
+ height: var(--dodo-ui-element-height-small);
47
+ width: var(--dodo-ui-element-height-small);
48
+ font-size: 0.9rem;
49
+ }
50
+ .dodo-ui-UtilityIcon.size--large {
51
+ height: var(--dodo-ui-element-height-large);
52
+ width: var(--dodo-ui-element-height-large);
53
+ font-size: 1.1rem;
54
+ }
55
+ .dodo-ui-UtilityIcon.disabled {
56
+ cursor: initial;
57
+ color: var(--dodo-ui-UtilityIcon-disabled-color);
58
+ }</style>
@@ -0,0 +1,19 @@
1
+ import type { ComponentSize } from '../../../../types/size.js';
2
+ import type { Snippet } from 'svelte';
3
+ export interface UtilityIconProps {
4
+ /** Button contents goes here*/
5
+ children?: Snippet;
6
+ /** Button ref */
7
+ ref?: HTMLSpanElement;
8
+ /** How large should the button be? */
9
+ size?: ComponentSize;
10
+ /** Button disabled state */
11
+ disabled?: boolean;
12
+ /** Id */
13
+ id?: string;
14
+ /** Custom css class*/
15
+ class?: string;
16
+ }
17
+ declare const UtilityIcon: import("svelte").Component<UtilityIconProps, {}, "ref">;
18
+ type UtilityIcon = ReturnType<typeof UtilityIcon>;
19
+ export default UtilityIcon;
@@ -1 +1 @@
1
- export type DropdownArrowPosition = false | 'before' | 'after';
1
+ export type IconPosition = false | 'before' | 'after';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flightlesslabs/dodo-ui",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "scripts": {
5
5
  "copy-css": "cpy src/lib/styles/global.css dist/styles --parents",
6
6
  "build": "vite build && pnpm copy-css && pnpm run prepack",
@@ -53,22 +53,22 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@chromatic-com/storybook": "4.1.0",
56
- "@eslint/compat": "^1.3.1",
57
- "@eslint/js": "^9.32.0",
56
+ "@eslint/compat": "^1.3.2",
57
+ "@eslint/js": "^9.33.0",
58
58
  "@storybook/addon-docs": "^9.1.1",
59
59
  "@storybook/addon-svelte-csf": "5.0.7",
60
60
  "@storybook/addon-vitest": "^9.1.1",
61
61
  "@storybook/sveltekit": "^9.1.1",
62
- "@sveltejs/adapter-static": "^3.0.8",
63
- "@sveltejs/kit": "^2.27.1",
64
- "@sveltejs/package": "^2.4.0",
65
- "@sveltejs/vite-plugin-svelte": "^6.1.0",
62
+ "@sveltejs/adapter-static": "^3.0.9",
63
+ "@sveltejs/kit": "^2.27.3",
64
+ "@sveltejs/package": "^2.4.1",
65
+ "@sveltejs/vite-plugin-svelte": "^6.1.1",
66
66
  "@types/file-saver": "^2.0.7",
67
67
  "@vitest/browser": "^3.2.4",
68
68
  "@vitest/coverage-v8": "^3.2.4",
69
69
  "@vueless/storybook-dark-mode": "^9.0.6",
70
70
  "cpy-cli": "^5.0.0",
71
- "eslint": "^9.32.0",
71
+ "eslint": "^9.33.0",
72
72
  "eslint-config-prettier": "^10.1.8",
73
73
  "eslint-plugin-storybook": "9.1.1",
74
74
  "eslint-plugin-svelte": "^3.11.0",
@@ -84,7 +84,7 @@
84
84
  "svelte-preprocess": "^6.0.3",
85
85
  "typescript": "^5.9.2",
86
86
  "typescript-eslint": "^8.39.0",
87
- "vite": "^7.1.0",
87
+ "vite": "^7.1.1",
88
88
  "vitest": "^3.2.4"
89
89
  },
90
90
  "keywords": [
package/src/lib/index.ts CHANGED
@@ -12,7 +12,7 @@ export type { ComponentWeight } from './types/weight.js';
12
12
 
13
13
  export type { PositionY, PositionX } from './types/position.js';
14
14
 
15
- export type { DropdownArrowPosition } from './types/special.js';
15
+ export type { IconPosition } from './types/special.js';
16
16
 
17
17
  /** developer tools: helpers: logger */
18
18
  export { default as createLogger } from '$lib/stories/developer tools/helpers/logger/logger.js';
@@ -134,6 +134,10 @@ export type { CheckboxProps } from '$lib/stories/components/Form/Checkbox/Checkb
134
134
  export { default as Radio } from '$lib/stories/components/Form/Radio/Radio.svelte';
135
135
  export type { RadioProps } from '$lib/stories/components/Form/Radio/Radio.svelte';
136
136
 
137
+ /** Form: Search */
138
+ export { default as Search } from '$lib/stories/components/Form/Search/Search.svelte';
139
+ export type { SearchProps } from '$lib/stories/components/Form/Search/Search.svelte';
140
+
137
141
  /** Layout: Paper */
138
142
  export { default as Paper } from '$lib/stories/components/Layout/Paper/Paper.svelte';
139
143
  export type { PaperColor, PaperProps } from '$lib/stories/components/Layout/Paper/Paper.svelte';
@@ -557,6 +557,7 @@
557
557
  : getMoment(value, undefined, { timezone, utc }).format(format)}
558
558
  {readonly}
559
559
  variant={editable ? 'input' : 'button'}
560
+ {size}
560
561
  >
561
562
  {#snippet customInputContent()}
562
563
  {#if customInputContentTyped}
@@ -281,6 +281,7 @@
281
281
  {readonly}
282
282
  variant="input"
283
283
  bind:value
284
+ {size}
284
285
  />
285
286
  </InputEnclosure>
286
287
  </div>
@@ -179,6 +179,7 @@
179
179
  bind:value
180
180
  {readonly}
181
181
  variant="input"
182
+ {size}
182
183
  />
183
184
 
184
185
  {#if passwordToggle && !disabled}
@@ -0,0 +1,285 @@
1
+ <script lang="ts" module>
2
+ import type { ComponentRoundness } from '$lib/types/roundness.js';
3
+ import type { ComponentSize } from '$lib/types/size.js';
4
+
5
+ import type { Snippet } from 'svelte';
6
+ import type {
7
+ ChangeEventHandler,
8
+ ClipboardEventHandler,
9
+ FocusEventHandler,
10
+ FormEventHandler,
11
+ KeyboardEventHandler,
12
+ } from 'svelte/elements';
13
+
14
+ export interface SearchProps {
15
+ /** Input ref */
16
+ ref?: HTMLInputElement;
17
+ /** How large should the button be? */
18
+ size?: ComponentSize;
19
+ /** How round should the border radius be? */
20
+ roundness?: ComponentRoundness;
21
+ /** Add a border around the button. Default True */
22
+ outline?: boolean;
23
+ /** Input value */
24
+ value?: string;
25
+ /** How round should the border radius be? */
26
+ placeholder?: string;
27
+ /** disabled state */
28
+ disabled?: boolean;
29
+ /** Read only ? */
30
+ readonly?: boolean;
31
+ /** is there any associated Error ? */
32
+ error?: boolean;
33
+ /** Name */
34
+ name?: string;
35
+ /** Id */
36
+ id?: string;
37
+ /** Icon before button content */
38
+ before?: Snippet;
39
+ /** Icon after button content */
40
+ after?: Snippet;
41
+ /** Custom css class*/
42
+ class?: string;
43
+ /** onsearch event handler */
44
+ onsearch?: () => void;
45
+ /** onclear event handler */
46
+ onclear?: () => void;
47
+ /** oninput event handler */
48
+ oninput?: FormEventHandler<HTMLInputElement>;
49
+ /** onchange event handler */
50
+ onchange?: ChangeEventHandler<HTMLInputElement>;
51
+ /** onblur event handler */
52
+ onblur?: FocusEventHandler<HTMLInputElement>;
53
+ /** onfocus event handler */
54
+ onfocus?: FocusEventHandler<HTMLInputElement>;
55
+ /** onpaste event handler */
56
+ onpaste?: ClipboardEventHandler<HTMLInputElement>;
57
+ /** oncopy event handler */
58
+ oncopy?: ClipboardEventHandler<HTMLInputElement>;
59
+ /** oncut event handler */
60
+ oncut?: ClipboardEventHandler<HTMLInputElement>;
61
+ /** onkeydown event handler */
62
+ onkeydown?: KeyboardEventHandler<HTMLInputElement>;
63
+ /** onkeypress event handler */
64
+ onkeypress?: KeyboardEventHandler<HTMLInputElement>;
65
+ /** onkeyup event handler */
66
+ onkeyup?: KeyboardEventHandler<HTMLInputElement>;
67
+ /** custom Search Icon */
68
+ customSearchIcon?: () => Snippet;
69
+ /** search Icon Position */
70
+ searchIconPosition?: IconPosition;
71
+ }
72
+ </script>
73
+
74
+ <script lang="ts">
75
+ import InputEnclosure from '$lib/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte';
76
+ import { type DynamicInputFocusEvent } from '$lib/stories/developer tools/components/DynamicInput/DynamicInput.svelte';
77
+ import type { TextInputFocusEvent, TextInputKeyboardEvent } from '../TextInput/TextInput.svelte';
78
+ import UtilityButton from '$lib/stories/developer tools/components/UtilityButton/UtilityButton.svelte';
79
+ import Icon from '@iconify/svelte';
80
+ import UtilityIcon from '$lib/stories/developer tools/components/UtilityIcon/UtilityIcon.svelte';
81
+ import type { IconPosition } from '$lib/types/special.js';
82
+
83
+ let {
84
+ size = 'normal',
85
+ roundness = 1,
86
+ outline = true,
87
+ name,
88
+ id,
89
+ class: className = '',
90
+ disabled = false,
91
+ onsearch,
92
+ onclear,
93
+ oninput,
94
+ onchange,
95
+ onblur,
96
+ onfocus,
97
+ onpaste,
98
+ oncopy,
99
+ oncut,
100
+ onkeydown,
101
+ onkeypress,
102
+ onkeyup,
103
+ before,
104
+ after,
105
+ error = false,
106
+ value = $bindable<string>(),
107
+ placeholder,
108
+ ref = $bindable<HTMLInputElement>(),
109
+ readonly = false,
110
+ customSearchIcon,
111
+ searchIconPosition = 'before',
112
+ }: SearchProps = $props();
113
+
114
+ let focused: boolean = $state(false);
115
+
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ let customSearchIconTyped = customSearchIcon as any;
118
+
119
+ function onfocusMod(e: DynamicInputFocusEvent) {
120
+ const eTyped = e as TextInputFocusEvent;
121
+ if (onfocus) {
122
+ onfocus(eTyped);
123
+ }
124
+ }
125
+
126
+ function onblurMod(e: DynamicInputFocusEvent) {
127
+ const eTyped = e as TextInputFocusEvent;
128
+
129
+ if (onblur) {
130
+ onblur(eTyped);
131
+ }
132
+ }
133
+
134
+ function onkeydownMod(e: TextInputKeyboardEvent) {
135
+ const eTyped = e as TextInputKeyboardEvent;
136
+
137
+ if (onkeydown) {
138
+ onkeydown(eTyped);
139
+ }
140
+
141
+ if (e.key === 'Enter' && onsearch) {
142
+ e.preventDefault();
143
+
144
+ onsearch();
145
+ return;
146
+ }
147
+
148
+ if (e.key === 'Escape' && onclear) {
149
+ e.preventDefault();
150
+
151
+ onclear();
152
+ return;
153
+ }
154
+ }
155
+ </script>
156
+
157
+ {#snippet searchIcon()}
158
+ <UtilityIcon {size} {disabled}>
159
+ {#if customSearchIconTyped}
160
+ {@render customSearchIconTyped()}
161
+ {:else}
162
+ <Icon icon="material-symbols:search-rounded" width="24" height="24" />
163
+ {/if}
164
+ </UtilityIcon>
165
+ {/snippet}
166
+
167
+ <div
168
+ class:outline
169
+ class:disabled
170
+ class:error
171
+ class:focused
172
+ class={['dodo-ui-Search', `size--${size}`, `roundness--${roundness}`, className].join(' ')}
173
+ >
174
+ <InputEnclosure {outline} {disabled} {error} {focused} {size} {roundness} {before} {after}>
175
+ {#if searchIconPosition === 'before'}
176
+ <div class="SearchIcon before">
177
+ {@render searchIcon()}
178
+ </div>
179
+ {/if}
180
+
181
+ <input
182
+ type="search"
183
+ {name}
184
+ {id}
185
+ {disabled}
186
+ bind:this={ref}
187
+ bind:focused
188
+ {oninput}
189
+ {onchange}
190
+ onfocus={onfocusMod}
191
+ onblur={onblurMod}
192
+ {onpaste}
193
+ {oncopy}
194
+ {oncut}
195
+ onkeydown={onkeydownMod}
196
+ onkeypress={onkeypress ? (e) => onkeypress(e as TextInputKeyboardEvent) : undefined}
197
+ onkeyup={onkeyup ? (e) => onkeyup(e as TextInputKeyboardEvent) : undefined}
198
+ {placeholder}
199
+ bind:value
200
+ {readonly}
201
+ />
202
+
203
+ {#if value && onclear && !disabled}
204
+ <div class="SearchClear">
205
+ <UtilityButton {size} title="Clear" onclick={onclear}>
206
+ <Icon icon="material-symbols:close-small" width="24" height="24" />
207
+ </UtilityButton>
208
+ </div>
209
+ {/if}
210
+
211
+ {#if searchIconPosition === 'after'}
212
+ <div class="SearchIcon after">
213
+ {@render searchIcon()}
214
+ </div>
215
+ {/if}
216
+ </InputEnclosure>
217
+ </div>
218
+
219
+ <style lang="scss">
220
+ .dodo-ui-Search {
221
+ input {
222
+ flex: 1;
223
+ border: 0;
224
+ outline: 0;
225
+ height: 100%;
226
+ background-color: transparent;
227
+ font-family: inherit;
228
+ color: inherit;
229
+ letter-spacing: 0.3px;
230
+ margin: 0;
231
+
232
+ &::-webkit-search-decoration,
233
+ &::-webkit-search-cancel-button,
234
+ &::-webkit-search-results-button,
235
+ &::-webkit-search-results-decoration {
236
+ display: none;
237
+ }
238
+ }
239
+
240
+ .SearchIcon {
241
+ display: flex;
242
+ }
243
+
244
+ &.size {
245
+ &--normal {
246
+ .SearchIcon {
247
+ &.before {
248
+ margin-right: calc(calc(var(--dodo-ui-space-small) * 2) * -1);
249
+ }
250
+ }
251
+
252
+ input {
253
+ font-size: 1rem;
254
+ padding: 0 calc(var(--dodo-ui-space-small) * 2);
255
+ }
256
+ }
257
+
258
+ &--small {
259
+ .SearchIcon {
260
+ &.before {
261
+ margin-right: calc(var(--dodo-ui-space) * -1);
262
+ }
263
+ }
264
+
265
+ input {
266
+ padding: 0 var(--dodo-ui-space);
267
+ font-size: 0.9rem;
268
+ }
269
+ }
270
+
271
+ &--large {
272
+ .SearchIcon {
273
+ &.before {
274
+ margin-right: calc(calc(var(--dodo-ui-space) * 2) * -1);
275
+ }
276
+ }
277
+
278
+ input {
279
+ font-size: 1.1rem;
280
+ padding: 0 calc(var(--dodo-ui-space) * 2);
281
+ }
282
+ }
283
+ }
284
+ }
285
+ </style>