@flightlesslabs/dodo-ui 0.7.2 → 0.9.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 (138) hide show
  1. package/dist/index.d.ts +18 -2
  2. package/dist/index.js +11 -0
  3. package/dist/stories/components/Form/NumericInput/Events/Events.stories.svelte +126 -0
  4. package/dist/stories/components/Form/NumericInput/Events/Events.stories.svelte.d.ts +18 -0
  5. package/dist/stories/components/Form/NumericInput/NumericInput.stories.svelte +79 -0
  6. package/dist/stories/components/Form/NumericInput/NumericInput.stories.svelte.d.ts +21 -0
  7. package/dist/stories/components/Form/NumericInput/NumericInput.svelte +161 -0
  8. package/dist/stories/components/Form/NumericInput/NumericInput.svelte.d.ts +69 -0
  9. package/dist/stories/components/Form/NumericInput/Validation/Validation.stories.svelte +84 -0
  10. package/dist/stories/components/Form/NumericInput/Validation/Validation.stories.svelte.d.ts +18 -0
  11. package/dist/stories/components/Form/PasswordInput/Events/Events.stories.svelte +27 -6
  12. package/dist/stories/components/Form/PasswordInput/PasswordInput.svelte +5 -3
  13. package/dist/stories/components/Form/PasswordInput/PasswordInput.svelte.d.ts +7 -1
  14. package/dist/stories/components/Form/Select/Customize/Customize.stories.svelte +16 -1
  15. package/dist/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte +59 -0
  16. package/dist/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte.d.ts +18 -0
  17. package/dist/stories/components/Form/Select/Events/Events.stories.svelte +27 -0
  18. package/dist/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte +54 -0
  19. package/dist/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte.d.ts +18 -0
  20. package/dist/stories/components/Form/Select/Positions/Positions.stories.svelte +83 -0
  21. package/dist/stories/components/Form/Select/Positions/Positions.stories.svelte.d.ts +18 -0
  22. package/dist/stories/components/Form/Select/Select.svelte +110 -123
  23. package/dist/stories/components/Form/Select/Select.svelte.d.ts +22 -3
  24. package/dist/stories/components/Form/TextInput/Events/Events.stories.svelte +27 -0
  25. package/dist/stories/components/Form/TextInput/TextInput.svelte +5 -3
  26. package/dist/stories/components/Form/TextInput/TextInput.svelte.d.ts +10 -1
  27. package/dist/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte +28 -0
  28. package/dist/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte.d.ts +18 -0
  29. package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte +51 -0
  30. package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte.d.ts +22 -0
  31. package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte +129 -0
  32. package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte.d.ts +81 -0
  33. package/dist/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte +46 -0
  34. package/dist/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte.d.ts +18 -0
  35. package/dist/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte +27 -0
  36. package/dist/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte.d.ts +18 -0
  37. package/dist/stories/components/Layout/Menu/DynamicMenu/Options/OptionFormat.mdx +72 -0
  38. package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.svelte.d.ts +1 -1
  39. package/dist/stories/developer tools/components/DynamicInput/DynamicInput.svelte +23 -4
  40. package/dist/stories/developer tools/components/DynamicInput/DynamicInput.svelte.d.ts +13 -2
  41. package/dist/stories/developer tools/components/DynamicInput/Events/Events.stories.svelte +115 -0
  42. package/dist/stories/developer tools/components/DynamicInput/Events/Events.stories.svelte.d.ts +18 -0
  43. package/dist/stories/developer tools/helpers/Numbers/cleanNumericString/cleanNumericString.d.ts +13 -0
  44. package/dist/stories/developer tools/helpers/Numbers/cleanNumericString/cleanNumericString.js +26 -0
  45. package/dist/stories/developer tools/helpers/Numbers/cleanNumericString/index.mdx +20 -0
  46. package/dist/stories/developer tools/helpers/Numbers/isValidNumberValue/index.mdx +71 -0
  47. package/dist/stories/developer tools/helpers/Numbers/isValidNumberValue/isValidNumberValue.d.ts +51 -0
  48. package/dist/stories/developer tools/helpers/Numbers/isValidNumberValue/isValidNumberValue.js +96 -0
  49. package/dist/stories/developer tools/helpers/logger/index.mdx +63 -0
  50. package/dist/stories/developer tools/helpers/logger/logger.d.ts +24 -0
  51. package/dist/stories/developer tools/helpers/logger/logger.js +31 -0
  52. package/package.json +15 -17
  53. package/src/lib/index.ts +33 -0
  54. package/src/lib/stories/Home.mdx +59 -0
  55. package/src/lib/stories/assets/dark-theme-toggle.png +0 -0
  56. package/src/lib/stories/components/Form/Button/Button.stories.svelte +61 -0
  57. package/src/lib/stories/components/Form/Button/Color/Color.stories.svelte +43 -0
  58. package/src/lib/stories/components/Form/Button/Events/Events.stories.svelte +36 -0
  59. package/src/lib/stories/components/Form/Button/IconButton/IconButton.stories.svelte +43 -0
  60. package/src/lib/stories/components/Form/Button/Roundness/Roundness.stories.svelte +23 -0
  61. package/src/lib/stories/components/Form/Button/Size/Size.stories.svelte +16 -0
  62. package/src/lib/stories/components/Form/Button/Variant/Variant.stories.svelte +18 -0
  63. package/src/lib/stories/components/Form/FormControl/FormControl.stories.svelte +28 -0
  64. package/src/lib/stories/components/Form/Label/Label.stories.svelte +13 -0
  65. package/src/lib/stories/components/Form/Message/Color/Color.stories.svelte +36 -0
  66. package/src/lib/stories/components/Form/Message/Message.stories.svelte +27 -0
  67. package/src/lib/stories/components/Form/Message/Size/Size.stories.svelte +22 -0
  68. package/src/lib/stories/components/Form/NumericInput/Events/Events.stories.svelte +134 -0
  69. package/src/lib/stories/components/Form/NumericInput/NumericInput.stories.svelte +84 -0
  70. package/src/lib/stories/components/Form/NumericInput/NumericInput.svelte +286 -0
  71. package/src/lib/stories/components/Form/NumericInput/Validation/Validation.stories.svelte +87 -0
  72. package/src/lib/stories/components/Form/PasswordInput/Events/Events.stories.svelte +132 -0
  73. package/src/lib/stories/components/Form/PasswordInput/PasswordInput.stories.svelte +59 -0
  74. package/src/lib/stories/components/Form/PasswordInput/PasswordInput.svelte +15 -3
  75. package/src/lib/stories/components/Form/PasswordInput/Roundness/Roundness.stories.svelte +20 -0
  76. package/src/lib/stories/components/Form/PasswordInput/Size/Size.stories.svelte +16 -0
  77. package/src/lib/stories/components/Form/PasswordInput/WithIcon/WithIcon.stories.svelte +31 -0
  78. package/src/lib/stories/components/Form/Select/Customize/Customize.stories.svelte +139 -0
  79. package/src/lib/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte +63 -0
  80. package/src/lib/stories/components/Form/Select/Events/Events.stories.svelte +174 -0
  81. package/src/lib/stories/components/Form/Select/Options/OptionFormat.mdx +40 -0
  82. package/src/lib/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte +58 -0
  83. package/src/lib/stories/components/Form/Select/Positions/Positions.stories.svelte +87 -0
  84. package/src/lib/stories/components/Form/Select/Roundness/Roundness.stories.svelte +32 -0
  85. package/src/lib/stories/components/Form/Select/Select.stories.svelte +121 -0
  86. package/src/lib/stories/components/Form/Select/Select.svelte +166 -146
  87. package/src/lib/stories/components/Form/Select/Size/Size.stories.svelte +28 -0
  88. package/src/lib/stories/components/Form/Select/WithIcon/WithIcon.stories.svelte +43 -0
  89. package/src/lib/stories/components/Form/TextInput/Events/Events.stories.svelte +125 -0
  90. package/src/lib/stories/components/Form/TextInput/Roundness/Roundness.stories.svelte +21 -0
  91. package/src/lib/stories/components/Form/TextInput/Size/Size.stories.svelte +17 -0
  92. package/src/lib/stories/components/Form/TextInput/TextInput.stories.svelte +43 -0
  93. package/src/lib/stories/components/Form/TextInput/TextInput.svelte +18 -3
  94. package/src/lib/stories/components/Form/TextInput/WithIcon/WithIcon.stories.svelte +47 -0
  95. package/src/lib/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte +30 -0
  96. package/src/lib/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte +56 -0
  97. package/src/lib/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte +262 -0
  98. package/src/lib/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte +48 -0
  99. package/src/lib/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte +29 -0
  100. package/src/lib/stories/components/Layout/Menu/DynamicMenu/Options/OptionFormat.mdx +72 -0
  101. package/src/lib/stories/components/Layout/Menu/Menu.stories.svelte +69 -0
  102. package/src/lib/stories/components/Layout/Menu/MenuItem/MenuItem.stories.svelte +34 -0
  103. package/src/lib/stories/components/Layout/Menu/MenuItem/MenuItem.svelte +1 -1
  104. package/src/lib/stories/components/Layout/Menu/MenuItem/Size/Size.stories.svelte +16 -0
  105. package/src/lib/stories/components/Layout/Menu/MenuItem/Type/Type.stories.svelte +21 -0
  106. package/src/lib/stories/components/Layout/Menu/Size/Size.stories.svelte +37 -0
  107. package/src/lib/stories/components/Layout/Paper/Color/Color.stories.svelte +63 -0
  108. package/src/lib/stories/components/Layout/Paper/Paper.stories.svelte +50 -0
  109. package/src/lib/stories/components/Layout/Paper/Roundness/Roundness.stories.svelte +25 -0
  110. package/src/lib/stories/components/Layout/Paper/Shadow/Shadow.stories.svelte +24 -0
  111. package/src/lib/stories/components/Layout/Separator/Color/Color.stories.svelte +19 -0
  112. package/src/lib/stories/components/Layout/Separator/Separator.stories.svelte +30 -0
  113. package/src/lib/stories/developer tools/Intro.mdx +9 -0
  114. package/src/lib/stories/developer tools/components/DynamicInput/DynamicInput.stories.svelte +53 -0
  115. package/src/lib/stories/developer tools/components/DynamicInput/DynamicInput.svelte +43 -3
  116. package/src/lib/stories/developer tools/components/DynamicInput/Events/Events.stories.svelte +121 -0
  117. package/src/lib/stories/developer tools/components/DynamicInput/Size/Size.stories.svelte +17 -0
  118. package/src/lib/stories/developer tools/components/InputEnclosure/InputEnclosure.stories.svelte +38 -0
  119. package/src/lib/stories/developer tools/components/InputEnclosure/Roundness/Roundness.stories.svelte +20 -0
  120. package/src/lib/stories/developer tools/components/InputEnclosure/Size/Size.stories.svelte +16 -0
  121. package/src/lib/stories/developer tools/components/InputEnclosure/WithIcon/WithIcon.stories.svelte +47 -0
  122. package/src/lib/stories/developer tools/components/Popper/Popper.stories.svelte +124 -0
  123. package/src/lib/stories/developer tools/components/Popper/PopperPopup/PopperPopup.stories.svelte +64 -0
  124. package/src/lib/stories/developer tools/components/Popper/Positions/AutoPosition/AutoPosition.stories.svelte +92 -0
  125. package/src/lib/stories/developer tools/components/Popper/Positions/Positions.stories.svelte +114 -0
  126. package/src/lib/stories/developer tools/components/UtilityButton/Size/Size.stories.svelte +25 -0
  127. package/src/lib/stories/developer tools/components/UtilityButton/UtilityButton.stories.svelte +30 -0
  128. package/src/lib/stories/developer tools/directives/clickOutside/index.mdx +25 -0
  129. package/src/lib/stories/developer tools/helpers/Numbers/cleanNumericString/cleanNumericString.ts +27 -0
  130. package/src/lib/stories/developer tools/helpers/Numbers/cleanNumericString/index.mdx +20 -0
  131. package/src/lib/stories/developer tools/helpers/Numbers/isValidNumberValue/index.mdx +71 -0
  132. package/src/lib/stories/developer tools/helpers/Numbers/isValidNumberValue/isValidNumberValue.ts +156 -0
  133. package/src/lib/stories/developer tools/helpers/logger/index.mdx +63 -0
  134. package/src/lib/stories/developer tools/helpers/logger/logger.ts +46 -0
  135. package/src/lib/stories/developer tools/philosophy/Colors/Colors.mdx +43 -0
  136. package/src/lib/stories/developer tools/philosophy/Colors/Colors.stories.svelte +22 -0
  137. package/src/lib/stories/developer tools/philosophy/Colors/Opacity.stories.svelte +11 -0
  138. package/src/lib/stories/developer tools/philosophy/Themes.mdx +23 -0
@@ -0,0 +1,129 @@
1
+ <script lang="ts" module>export {};
2
+ </script>
3
+
4
+ <script lang="ts">import Menu from '../Menu.svelte';
5
+ import { MenuItem } from '../../../../../index.js';
6
+ let { id, class: className = '', ref = $bindable(), size, separator, width, height, options, selectedOption, customMenuItemContent, customPlaceholderMenuItemContent, menuItemProps, keyboardNavigation = false, onEnter, onEsc, onclick, showOptionsPlaceholder = false, optionsPlaceholder = 'No options found', } = $props();
7
+ let menuItemIndex = $state(0);
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ let customMenuItemContentTyped = customMenuItemContent;
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ let customPlaceholderMenuItemContentTyped = customPlaceholderMenuItemContent;
12
+ function onKeyboardNavigation(e) {
13
+ let keyHit = undefined;
14
+ if (!ref) {
15
+ return;
16
+ }
17
+ switch (e.key) {
18
+ case 'ArrowDown':
19
+ case 'ArrowUp':
20
+ keyHit = e.key;
21
+ e.preventDefault();
22
+ break;
23
+ case 'Enter':
24
+ case 'Esc':
25
+ keyHit = e.key;
26
+ break;
27
+ default:
28
+ break;
29
+ }
30
+ if (!keyHit) {
31
+ return;
32
+ }
33
+ if (keyHit === 'Enter') {
34
+ if (onEnter) {
35
+ onEnter(e, menuItemIndex);
36
+ }
37
+ return;
38
+ }
39
+ else if (keyHit === 'Escape') {
40
+ if (onEsc) {
41
+ onEsc(e, menuItemIndex);
42
+ }
43
+ return;
44
+ }
45
+ const listItems = ref.querySelectorAll(':scope > li.dodo-ui-MenuItem');
46
+ if (!listItems.length) {
47
+ return;
48
+ }
49
+ for (let index = 0; index < listItems.length; index++) {
50
+ const element = listItems[index];
51
+ element.classList.remove('hover');
52
+ }
53
+ let newMenuItemIndex = menuItemIndex;
54
+ if (keyHit === 'ArrowDown') {
55
+ if (listItems[newMenuItemIndex + 1]) {
56
+ newMenuItemIndex = newMenuItemIndex + 1;
57
+ }
58
+ else {
59
+ newMenuItemIndex = 0;
60
+ }
61
+ }
62
+ else if (keyHit === 'ArrowUp') {
63
+ if (listItems[newMenuItemIndex - 1]) {
64
+ newMenuItemIndex = newMenuItemIndex - 1;
65
+ }
66
+ else {
67
+ newMenuItemIndex = listItems.length - 1;
68
+ }
69
+ }
70
+ const targetItem = listItems[newMenuItemIndex];
71
+ targetItem.classList.add('hover');
72
+ targetItem.focus();
73
+ targetItem.scrollIntoView({ block: 'nearest' });
74
+ menuItemIndex = newMenuItemIndex;
75
+ }
76
+ $effect(() => {
77
+ if (!keyboardNavigation) {
78
+ return;
79
+ }
80
+ const targetItem = ref.querySelector(':scope > li.dodo-ui-MenuItem.selected');
81
+ if (targetItem) {
82
+ const selectedIndex = options?.findIndex((option) => option.id === selectedOption?.id);
83
+ if (selectedIndex !== undefined && selectedIndex >= 0) {
84
+ menuItemIndex = selectedIndex;
85
+ }
86
+ targetItem.focus();
87
+ targetItem.scrollIntoView({ block: 'nearest' });
88
+ }
89
+ window.addEventListener('keydown', onKeyboardNavigation);
90
+ return () => {
91
+ window.removeEventListener('keydown', onKeyboardNavigation);
92
+ };
93
+ });
94
+ </script>
95
+
96
+ <Menu
97
+ class={['dodo-ui-DynamicMenu', className].join(' ')}
98
+ {id}
99
+ {size}
100
+ {width}
101
+ {height}
102
+ {separator}
103
+ bind:ref
104
+ >
105
+ {#if options?.length}
106
+ {#each options as option (option.id)}
107
+ <MenuItem
108
+ {...option}
109
+ selected={selectedOption?.id === option.id}
110
+ onclick={(e) => (onclick ? onclick(e, option) : undefined)}
111
+ {...menuItemProps}
112
+ >
113
+ {#if customMenuItemContentTyped}
114
+ {@render customMenuItemContentTyped(option, selectedOption)}
115
+ {:else}
116
+ {option.label || ''}
117
+ {/if}
118
+ </MenuItem>
119
+ {/each}
120
+ {:else if showOptionsPlaceholder}
121
+ <MenuItem type="text" disabled={true} {...menuItemProps}>
122
+ {#if customPlaceholderMenuItemContentTyped}
123
+ {@render customPlaceholderMenuItemContentTyped()}
124
+ {:else}
125
+ {optionsPlaceholder}
126
+ {/if}
127
+ </MenuItem>
128
+ {/if}
129
+ </Menu>
@@ -0,0 +1,81 @@
1
+ import type { ComponentSize } from '../../../../../types/size.js';
2
+ import type { MenuItemProps, MenuItemType } from '../MenuItem/MenuItem.svelte';
3
+ export type DynamicMenuItemOption<TMeta = unknown> = {
4
+ id: string;
5
+ /** label */
6
+ label?: string;
7
+ /** Custom Metadata */
8
+ meta?: TMeta;
9
+ /** Menu Item type */
10
+ type?: MenuItemType;
11
+ /** Menu Separator */
12
+ separator?: boolean;
13
+ /** How large should the Menu Items be? */
14
+ size?: ComponentSize;
15
+ /** The onclick event handler */
16
+ onclick?: MouseEventHandler<HTMLButtonElement>;
17
+ /** disabled state */
18
+ disabled?: boolean;
19
+ /** link href */
20
+ href?: string;
21
+ /** Link button: download */
22
+ download?: any;
23
+ /** Link button: hreflang */
24
+ hreflang?: string | undefined | null;
25
+ /** Link button: media */
26
+ media?: string | undefined | null;
27
+ /** Link button: ping */
28
+ ping?: string | undefined | null;
29
+ /** Link button: rel */
30
+ rel?: string | undefined | null;
31
+ /** Link button: target */
32
+ target?: ButtonLinkTarget;
33
+ /** Link button: Type */
34
+ anchorMediaType?: string | undefined | null;
35
+ /** Link button: referrerpolicy */
36
+ referrerpolicy?: ButtonLinkReferrerpolicy;
37
+ };
38
+ export interface DynamicMenuProps {
39
+ /** Menu ref */
40
+ ref?: HTMLUListElement;
41
+ /** Custom css class */
42
+ class?: string;
43
+ /** Menu Width */
44
+ width?: string;
45
+ /** Menu Height */
46
+ height?: string;
47
+ /** How large should the Menu Items be? */
48
+ size?: ComponentSize;
49
+ /** Menu Separator */
50
+ separator?: boolean;
51
+ /** Id */
52
+ id?: string;
53
+ /** Options */
54
+ options?: DynamicMenuItemOption[];
55
+ /** Selected Option */
56
+ selectedOption?: DynamicMenuItemOption;
57
+ /** Custom Menu Item Content */
58
+ customMenuItemContent?: (option: DynamicMenuItemOption, selectedOption?: DynamicMenuItemOption) => Snippet;
59
+ /** Show Placeholder if no options */
60
+ showOptionsPlaceholder?: boolean;
61
+ /** placeholder Text if no options */
62
+ optionsPlaceholder?: string;
63
+ /** Custom Menu Item Placeholder Content */
64
+ customPlaceholderMenuItemContent?: () => Snippet;
65
+ /** MenuItem: Menu component props */
66
+ menuItemProps?: Partial<MenuItemProps>;
67
+ /** Enable Keyboard Navigation */
68
+ keyboardNavigation?: boolean;
69
+ /** Keyboard Navigation onEnter */
70
+ onEnter?: (e: KeyboardEvent, menuItemIndex: number) => void;
71
+ /** Keyboard Navigation onEsc */
72
+ onEsc?: (e: KeyboardEvent, menuItemIndex: number) => void;
73
+ /** On menu item click */
74
+ onclick?: (e: MouseEvent, option: DynamicMenuItemOption) => void;
75
+ }
76
+ import type { MouseEventHandler } from 'svelte/elements';
77
+ import type { ButtonLinkReferrerpolicy, ButtonLinkTarget } from '../../../Form/Button/Button.svelte';
78
+ import type { Snippet } from 'svelte';
79
+ declare const DynamicMenu: import("svelte").Component<DynamicMenuProps, {}, "ref">;
80
+ type DynamicMenu = ReturnType<typeof DynamicMenu>;
81
+ export default DynamicMenu;
@@ -0,0 +1,46 @@
1
+ <script module lang="ts">import { defineMeta } from '@storybook/addon-svelte-csf';
2
+ import { dynamicMenuItemOptions, storyDynamicMenuArgTypes } from '../DynamicMenu.stories.svelte';
3
+ import DynamicMenu, {} from '../DynamicMenu.svelte';
4
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
5
+ const { Story } = defineMeta({
6
+ component: DynamicMenu,
7
+ tags: ['autodocs'],
8
+ argTypes: storyDynamicMenuArgTypes,
9
+ });
10
+ </script>
11
+
12
+ <!-- Menu Item onclick -->
13
+ <Story name="onclick" asChild>
14
+ <DynamicMenu
15
+ keyboardNavigation
16
+ options={dynamicMenuItemOptions}
17
+ onclick={(e: MouseEvent, option: DynamicMenuItemOption) => {
18
+ e.preventDefault();
19
+ console.log(option);
20
+ }}
21
+ />
22
+ </Story>
23
+
24
+ <!-- KeyboardNavigation Event: onEnter -->
25
+ <Story name="onEnter" asChild>
26
+ <DynamicMenu
27
+ keyboardNavigation
28
+ options={dynamicMenuItemOptions}
29
+ onEnter={(e: KeyboardEvent, menuItemIndex: number) => {
30
+ e.preventDefault();
31
+ console.log(menuItemIndex);
32
+ }}
33
+ />
34
+ </Story>
35
+
36
+ <!-- KeyboardNavigation Event: onEsc -->
37
+ <Story name="onEsc" asChild>
38
+ <DynamicMenu
39
+ keyboardNavigation
40
+ options={dynamicMenuItemOptions}
41
+ onEsc={(e: KeyboardEvent, menuItemIndex: number) => {
42
+ e.preventDefault();
43
+ console.log(menuItemIndex);
44
+ }}
45
+ />
46
+ </Story>
@@ -0,0 +1,18 @@
1
+ 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> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Events: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Events = InstanceType<typeof Events>;
18
+ export default Events;
@@ -0,0 +1,27 @@
1
+ <script module lang="ts">import { defineMeta } from '@storybook/addon-svelte-csf';
2
+ import DynamicMenu from '../DynamicMenu.svelte';
3
+ import { dynamicMenuItemOptions, storyDynamicMenuArgTypes } from '../DynamicMenu.stories.svelte';
4
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
5
+ const { Story } = defineMeta({
6
+ component: DynamicMenu,
7
+ tags: ['autodocs'],
8
+ argTypes: storyDynamicMenuArgTypes,
9
+ });
10
+ </script>
11
+
12
+ <!-- KeyboardNavigationOn -->
13
+ <Story
14
+ name="KeyboardNavigationOn"
15
+ args={{
16
+ options: dynamicMenuItemOptions,
17
+ keyboardNavigation: true,
18
+ onEnter: (e: KeyboardEvent, menuItemIndex: number) => {
19
+ e.preventDefault();
20
+ console.log(menuItemIndex);
21
+ },
22
+ onEsc: (e: KeyboardEvent, menuItemIndex: number) => {
23
+ e.preventDefault();
24
+ console.log(menuItemIndex);
25
+ },
26
+ }}
27
+ />
@@ -0,0 +1,18 @@
1
+ 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> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const KeybaordNavigation: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type KeybaordNavigation = InstanceType<typeof KeybaordNavigation>;
18
+ export default KeybaordNavigation;
@@ -0,0 +1,72 @@
1
+ import { Source } from '@storybook/blocks';
2
+
3
+ # Option Format
4
+
5
+ ## DynamicMenuItemOption
6
+
7
+ <Source
8
+ dark
9
+ language="ts"
10
+ code={`
11
+ type DynamicMenuItemOption<TMeta = unknown> = {
12
+ id: string;
13
+ /** label */
14
+ label?: string;
15
+ /** Custom Metadata */
16
+ meta?: TMeta;
17
+ /** Menu Item type */
18
+ type?: MenuItemType;
19
+ /** Menu Separator */
20
+ separator?: boolean;
21
+ /** How large should the Menu Items be? */
22
+ size?: ComponentSize;
23
+ /** The onclick event handler */
24
+ onclick?: MouseEventHandler<HTMLButtonElement>;
25
+ /** disabled state */
26
+ disabled?: boolean;
27
+ /** link href */
28
+ href?: string;
29
+ /** Link button: download */
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ download?: any;
32
+ /** Link button: hreflang */
33
+ hreflang?: string | undefined | null;
34
+ /** Link button: media */
35
+ media?: string | undefined | null;
36
+ /** Link button: ping */
37
+ ping?: string | undefined | null;
38
+ /** Link button: rel */
39
+ rel?: string | undefined | null;
40
+ /** Link button: target */
41
+ target?: ButtonLinkTarget;
42
+ /** Link button: Type */
43
+ anchorMediaType?: string | undefined | null;
44
+ /** Link button: referrerpolicy */
45
+ referrerpolicy?: ButtonLinkReferrerpolicy;
46
+ };
47
+ `}
48
+ />
49
+
50
+ ## Example values
51
+
52
+ <Source
53
+ dark
54
+ language="ts"
55
+ code={`
56
+ const options: DynamicMenuItemOption[] = [
57
+ {
58
+ id: '1',
59
+ label: 'One',
60
+ },
61
+ {
62
+ id: '2',
63
+ label: 'Two',
64
+ },
65
+ {
66
+ id: '3',
67
+ label: 'Three',
68
+ disabled: true,
69
+ },
70
+ ];
71
+ `}
72
+ />
@@ -14,7 +14,7 @@ export interface MenuItemProps {
14
14
  id?: string;
15
15
  /** Menu Item type */
16
16
  type?: MenuItemType;
17
- /** Menu Item type */
17
+ /** selected */
18
18
  selected?: boolean;
19
19
  /** Separator */
20
20
  separator?: boolean;
@@ -3,7 +3,7 @@ export const dynamicInputVariantArray = ['input', 'button'];
3
3
  </script>
4
4
 
5
5
  <script lang="ts">"use strict";
6
- let { type = 'text', name, id, class: className = '', disabled = false, onchange, oninput, onblur, onfocus, onpaste, oncopy, oncut, value = $bindable(), placeholder, ref = $bindable(), readonly = false, variant = 'input', size = 'normal', onclick, customInputContent, } = $props();
6
+ let { type = 'text', name, id, class: className = '', disabled = false, onchange, oninput, onblur, onfocus, onpaste, oncopy, oncut, onkeydown, onkeypress, onkeyup, value = $bindable(), focused = $bindable(), placeholder, ref = $bindable(), readonly = false, variant = 'input', size = 'normal', onclick, customInputContent, } = $props();
7
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
8
  let customInputContentTyped = customInputContent;
9
9
  function onclickMod(e) {
@@ -14,6 +14,18 @@ function onclickMod(e) {
14
14
  onclick(e);
15
15
  }
16
16
  }
17
+ function onfocusMod(e) {
18
+ focused = true;
19
+ if (onfocus) {
20
+ onfocus(e);
21
+ }
22
+ }
23
+ function onblurMod(e) {
24
+ focused = false;
25
+ if (onblur) {
26
+ onblur(e);
27
+ }
28
+ }
17
29
  </script>
18
30
 
19
31
  {#if variant === 'button'}
@@ -28,7 +40,11 @@ function onclickMod(e) {
28
40
  ].join(' ')}
29
41
  bind:this={ref}
30
42
  onclick={onclickMod}
31
- {onblur}
43
+ {onkeydown}
44
+ {onkeypress}
45
+ {onkeyup}
46
+ onfocus={onfocusMod}
47
+ onblur={onblurMod}
32
48
  {disabled}
33
49
  >
34
50
  {#if customInputContentTyped}
@@ -46,11 +62,14 @@ function onclickMod(e) {
46
62
  {disabled}
47
63
  {oninput}
48
64
  {onchange}
49
- {onfocus}
50
- {onblur}
65
+ onfocus={onfocusMod}
66
+ onblur={onblurMod}
51
67
  {onpaste}
52
68
  {oncopy}
53
69
  {oncut}
70
+ {onkeydown}
71
+ {onkeypress}
72
+ {onkeyup}
54
73
  {placeholder}
55
74
  bind:value
56
75
  bind:this={ref}
@@ -1,6 +1,6 @@
1
1
  import { type ComponentSize, type TextInputType } from '../../../../index.js';
2
2
  import type { Snippet } from 'svelte';
3
- import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler, MouseEventHandler } from 'svelte/elements';
3
+ import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler, KeyboardEventHandler, MouseEventHandler } from 'svelte/elements';
4
4
  export type DynamicInputVariant = 'input' | 'button';
5
5
  export declare const dynamicInputVariantArray: DynamicInputVariant[];
6
6
  export type DynamicInputClickEvent = MouseEvent & {
@@ -9,6 +9,9 @@ export type DynamicInputClickEvent = MouseEvent & {
9
9
  export type DynamicInputFocusEvent = FocusEvent & {
10
10
  currentTarget: EventTarget & (HTMLInputElement | HTMLButtonElement);
11
11
  };
12
+ export type DynamicInputKeyboardEvent = KeyboardEvent & {
13
+ currentTarget: EventTarget & (HTMLInputElement | HTMLButtonElement);
14
+ };
12
15
  export interface DynamicInputProps {
13
16
  /** How large should the button be? */
14
17
  size?: ComponentSize;
@@ -18,6 +21,8 @@ export interface DynamicInputProps {
18
21
  ref?: HTMLInputElement | HTMLButtonElement;
19
22
  /** Input value */
20
23
  value?: string | number;
24
+ /** is focused, set focused */
25
+ focused?: boolean;
21
26
  /** variant */
22
27
  variant?: DynamicInputVariant;
23
28
  /** How round should the border radius be? */
@@ -52,9 +57,15 @@ export interface DynamicInputProps {
52
57
  oncopy?: ClipboardEventHandler<HTMLInputElement>;
53
58
  /** oncut event handler */
54
59
  oncut?: ClipboardEventHandler<HTMLInputElement>;
60
+ /** onkeydown event handler */
61
+ onkeydown?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
62
+ /** onkeypress event handler */
63
+ onkeypress?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
64
+ /** onkeyup event handler */
65
+ onkeyup?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
55
66
  /** custom Content Formatting for variant button */
56
67
  customInputContent?: (value: string | number) => Snippet;
57
68
  }
58
- declare const DynamicInput: import("svelte").Component<DynamicInputProps, {}, "ref" | "value">;
69
+ declare const DynamicInput: import("svelte").Component<DynamicInputProps, {}, "ref" | "focused" | "value">;
59
70
  type DynamicInput = ReturnType<typeof DynamicInput>;
60
71
  export default DynamicInput;
@@ -0,0 +1,115 @@
1
+ <script module lang="ts">import { defineMeta } from '@storybook/addon-svelte-csf';
2
+ import { storyDynamicInputArgTypes } from '../DynamicInput.stories.svelte';
3
+ import DynamicInput, {} from '../DynamicInput.svelte';
4
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
5
+ const { Story } = defineMeta({
6
+ component: DynamicInput,
7
+ tags: ['autodocs'],
8
+ argTypes: storyDynamicInputArgTypes,
9
+ args: { value: 'Hello world!' },
10
+ });
11
+ </script>
12
+
13
+ <Story
14
+ name="Input"
15
+ args={{
16
+ oninput: (e: Event) => {
17
+ const target = e.target as HTMLInputElement;
18
+
19
+ console.log('Input Event', target.value);
20
+ },
21
+ }}
22
+ />
23
+
24
+ <Story
25
+ name="Change"
26
+ args={{
27
+ onchange: (e: Event) => {
28
+ const target = e.target as HTMLInputElement;
29
+
30
+ console.log('onChange Event', target.value);
31
+ },
32
+ }}
33
+ />
34
+
35
+ <Story
36
+ name="Focus"
37
+ args={{
38
+ onfocus: (e: DynamicInputFocusEvent) => {
39
+ const target = e.target as HTMLInputElement;
40
+
41
+ console.log('onfocus Event', target);
42
+ },
43
+ }}
44
+ />
45
+
46
+ <Story
47
+ name="Blur"
48
+ args={{
49
+ onblur: (e: DynamicInputFocusEvent) => {
50
+ const target = e.target as HTMLInputElement;
51
+
52
+ console.log('onblur Event', target);
53
+ },
54
+ }}
55
+ />
56
+
57
+ <Story
58
+ name="Copy"
59
+ args={{
60
+ oncopy: (e: TextInputClipboardEvent) => {
61
+ const target = e.target as HTMLInputElement;
62
+
63
+ console.log('oncopy Event', target);
64
+ },
65
+ }}
66
+ />
67
+
68
+ <Story
69
+ name="Cut"
70
+ args={{
71
+ oncut: (e: TextInputClipboardEvent) => {
72
+ const target = e.target as HTMLInputElement;
73
+
74
+ console.log('oncut Event', target);
75
+ },
76
+ }}
77
+ />
78
+
79
+ <Story
80
+ name="Paste"
81
+ args={{
82
+ onpaste: (e: TextInputClipboardEvent) => {
83
+ const target = e.target as HTMLInputElement;
84
+
85
+ console.log('onpaste Event', target);
86
+ },
87
+ }}
88
+ />
89
+
90
+ <Story
91
+ name="KeyDown"
92
+ args={{
93
+ onkeydown: (e: DynamicInputKeyboardEvent) => {
94
+ console.log('onkeydown Event', e.key);
95
+ },
96
+ }}
97
+ />
98
+
99
+ <Story
100
+ name="KeyPress"
101
+ args={{
102
+ onkeypress: (e: DynamicInputKeyboardEvent) => {
103
+ console.log('onkeypress Event', e.key);
104
+ },
105
+ }}
106
+ />
107
+
108
+ <Story
109
+ name="KeyUp"
110
+ args={{
111
+ onkeyup: (e: DynamicInputKeyboardEvent) => {
112
+ console.log('onkeyup Event', e.key);
113
+ },
114
+ }}
115
+ />
@@ -0,0 +1,18 @@
1
+ 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> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Events: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Events = InstanceType<typeof Events>;
18
+ export default Events;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Cleans the input string by removing all characters except numeric digits (0-9) and a single decimal point.
3
+ * Only the first decimal point is retained; all subsequent dots are removed.
4
+ *
5
+ * @param {string} input - The input string to be cleaned.
6
+ * @returns {string} - A string containing only digits and at most one decimal point.
7
+ *
8
+ * @example
9
+ * cleanNumericString("abc123.45.67def"); // returns "123.4567"
10
+ * cleanNumericString("a1b2c3"); // returns "123"
11
+ * cleanNumericString("...12.3.4..5"); // returns "12.345"
12
+ */
13
+ export default function cleanNumericString(input: string): string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Cleans the input string by removing all characters except numeric digits (0-9) and a single decimal point.
3
+ * Only the first decimal point is retained; all subsequent dots are removed.
4
+ *
5
+ * @param {string} input - The input string to be cleaned.
6
+ * @returns {string} - A string containing only digits and at most one decimal point.
7
+ *
8
+ * @example
9
+ * cleanNumericString("abc123.45.67def"); // returns "123.4567"
10
+ * cleanNumericString("a1b2c3"); // returns "123"
11
+ * cleanNumericString("...12.3.4..5"); // returns "12.345"
12
+ */
13
+ export default function cleanNumericString(input) {
14
+ // Remove all characters except digits and dots
15
+ const filtered = input.replace(/[^0-9.]/g, '');
16
+ // Split by dot to separate parts
17
+ const parts = filtered.split('.');
18
+ if (parts.length === 1) {
19
+ // No dot present, just digits
20
+ return parts[0];
21
+ }
22
+ else {
23
+ // Keep only first dot, join the rest parts without dots
24
+ return parts[0] + '.' + parts.slice(1).join('');
25
+ }
26
+ }