@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
@@ -4,26 +4,35 @@
4
4
  <script lang="ts">import InputEnclosure from '../../../developer tools/components/InputEnclosure/InputEnclosure.svelte';
5
5
  import UtilityButton from '../../../developer tools/components/UtilityButton/UtilityButton.svelte';
6
6
  import Icon from '@iconify/svelte';
7
- import { DynamicInput, Menu, MenuItem, Popper, } from '../../../../index.js';
8
- let { size = 'normal', roundness = 1, outline = true, name, id, class: className = '', disabled = false, onchange, oninput, onselect, onblur, onfocus, onpaste, oncopy, oncut, before, after, error = false, value, placeholder, ref = $bindable(), readonly = false, searchable = false, clearable = false, onclear, options: optionsRaw, customInputContent: customInputContentInternal, customMenuItemContent: customMenuItemContentInternal, customPopupContent: customPopupContentInternal, customPlaceholderMenuItemContent: customPlaceholderMenuItemContentInternal, popupMaxHeight = '300px', paperProps, popperProps, menuProps, menuItemProps, optionsPlaceholder = 'No Options', } = $props();
7
+ import { DynamicInput, DynamicMenu, Popper, } from '../../../../index.js';
8
+ let { size = 'normal', roundness = 1, outline = true, name, id, class: className = '', disabled = false, onchange, oninput, onselect, onblur, onfocus, onpaste, oncopy, oncut, onkeydown, onkeypress, onkeyup, before, after, error = false, value, placeholder, ref = $bindable(), readonly = false, searchable = false, clearable = false, onclear, options: optionsRaw, customInputContent: customInputContentInternal, customMenuItemContent: customMenuItemContentInternal, customPopupContent: customPopupContentInternal, customPlaceholderMenuItemContent: customPlaceholderMenuItemContentInternal, customDropdownArrowIcon: customDropdownArrowIconInternal, popupMaxHeight = '300px', paperProps, popperProps, menuProps, menuItemProps, optionsPlaceholder = 'No Options', dropdownArrowPosition = 'after', popupPositionX, popupPositionY, lockPoistions, popperHeightForVerticalPosition, } = $props();
9
+ function convertOptionsToDynamicMenuItemOptions(options) {
10
+ const newOptions = options.map((option) => ({
11
+ id: `opt-${option.value}`,
12
+ disabled: option.disabled,
13
+ label: option.label,
14
+ meta: option,
15
+ type: 'button',
16
+ }));
17
+ return newOptions;
18
+ }
9
19
  let open = $state(false);
10
20
  let onInputStart = $state(false);
11
21
  const selectedOption = $derived(value);
12
22
  let searchTerm = $state(value?.label.trim() || '');
13
- let options = $state(optionsRaw);
23
+ let options = $state(convertOptionsToDynamicMenuItemOptions(optionsRaw));
14
24
  let menuRef = $state(undefined);
15
- let menuItemIndex = $state(0);
16
25
  $effect(() => {
17
26
  if (!onInputStart) {
18
- options = optionsRaw;
27
+ options = convertOptionsToDynamicMenuItemOptions(optionsRaw);
19
28
  return;
20
29
  }
21
30
  const searchTermSimplified = searchTerm.trim().toLowerCase();
22
31
  if (!searchTermSimplified) {
23
- options = optionsRaw;
32
+ options = convertOptionsToDynamicMenuItemOptions(optionsRaw);
24
33
  return;
25
34
  }
26
- options = optionsRaw.filter((item) => item.label.trim().toLowerCase().includes(searchTermSimplified));
35
+ options = convertOptionsToDynamicMenuItemOptions(optionsRaw).filter((item) => item?.meta?.label.trim().toLowerCase().includes(searchTermSimplified));
27
36
  });
28
37
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
38
  let customInputContentTyped = customInputContentInternal;
@@ -33,20 +42,14 @@ let customMenuItemContentTyped = customMenuItemContentInternal;
33
42
  let customPopupContentTyped = customPopupContentInternal;
34
43
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
44
  let customPlaceholderMenuItemContentTyped = customPlaceholderMenuItemContentInternal;
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ let customDropdownArrowIconTyped = customDropdownArrowIconInternal;
36
47
  function closeMenu() {
37
48
  open = false;
38
- menuItemIndex = 0;
39
49
  ref?.blur();
40
50
  }
41
51
  function openMenu() {
42
52
  open = true;
43
- const menuItemIndexNew = options.findIndex((item) => item.value === selectedOption?.value);
44
- if (menuItemIndexNew < 0) {
45
- menuItemIndex = 0;
46
- }
47
- else {
48
- menuItemIndex = menuItemIndexNew;
49
- }
50
53
  }
51
54
  function onfocusMod(e) {
52
55
  openMenu();
@@ -88,7 +91,8 @@ function onclearMod(e) {
88
91
  onclear(e);
89
92
  }
90
93
  }
91
- function onKeyBoardEnter(selectedItemIndex) {
94
+ function onKeyBoardEnter(e, selectedItemIndex) {
95
+ e.preventDefault();
92
96
  const targetOption = options[selectedItemIndex];
93
97
  if (!targetOption) {
94
98
  return;
@@ -96,86 +100,35 @@ function onKeyBoardEnter(selectedItemIndex) {
96
100
  if (targetOption.disabled) {
97
101
  return;
98
102
  }
99
- onselectMod(targetOption);
103
+ onselectMod(targetOption.meta);
100
104
  }
101
- function onKeyboardNavigation(e) {
102
- let keyHit = undefined;
103
- if (!menuRef) {
104
- return;
105
- }
106
- if (!open) {
107
- return;
108
- }
109
- switch (e.key) {
110
- case 'ArrowDown':
111
- case 'ArrowUp':
112
- case 'Enter':
113
- keyHit = e.key;
114
- e.preventDefault();
115
- break;
116
- default:
117
- break;
118
- }
119
- if (!keyHit) {
120
- return;
121
- }
122
- const listItems = menuRef.querySelectorAll(':scope > li.dodo-ui-MenuItem');
123
- if (!listItems.length) {
124
- return;
125
- }
126
- for (let index = 0; index < listItems.length; index++) {
127
- const element = listItems[index];
128
- element.classList.remove('hover');
129
- }
130
- let newMenuItemIndex = menuItemIndex;
131
- if (keyHit === 'ArrowDown') {
132
- if (listItems[newMenuItemIndex + 1]) {
133
- newMenuItemIndex = newMenuItemIndex + 1;
134
- }
135
- else {
136
- newMenuItemIndex = 0;
137
- }
138
- }
139
- else if (keyHit === 'ArrowUp') {
140
- if (listItems[newMenuItemIndex - 1]) {
141
- newMenuItemIndex = newMenuItemIndex - 1;
142
- }
143
- else {
144
- newMenuItemIndex = listItems.length - 1;
145
- }
146
- }
147
- else if (keyHit === 'Enter') {
148
- onKeyBoardEnter(newMenuItemIndex);
149
- return;
150
- }
151
- const targetItem = listItems[newMenuItemIndex];
152
- targetItem.classList.add('hover');
153
- targetItem.focus();
154
- targetItem.scrollIntoView({ block: 'nearest' });
155
- menuItemIndex = newMenuItemIndex;
156
- }
157
- $effect(() => {
158
- if (!menuRef) {
159
- return;
160
- }
161
- if (!open) {
162
- return;
163
- }
164
- const targetItem = menuRef.querySelector(':scope > li.dodo-ui-MenuItem.selected');
165
- if (targetItem) {
166
- targetItem.classList.add('hover');
167
- targetItem.focus();
168
- targetItem.scrollIntoView({ block: 'nearest' });
169
- }
170
- window.addEventListener('keydown', onKeyboardNavigation);
171
- return () => {
172
- window.removeEventListener('keydown', onKeyboardNavigation);
173
- };
174
- });
175
105
  </script>
176
106
 
107
+ {#snippet selectDropdownArrowIcon()}
108
+ <UtilityButton {size} title="Dropdown" onclick={onfocusMod}>
109
+ {#if customDropdownArrowIconTyped}
110
+ {@render customDropdownArrowIconTyped(open)}
111
+ {:else if open}
112
+ <Icon icon="material-symbols:arrow-drop-up-rounded" width="28" height="28" />
113
+ {:else}
114
+ <Icon icon="material-symbols:arrow-drop-down-rounded" width="28" height="28" />
115
+ {/if}
116
+ </UtilityButton>
117
+ {/snippet}
118
+
177
119
  <div class={['dodo-ui-Select', className].join(' ')}>
178
- <Popper fullWidth {open} {onClickOutside} {...popperProps} {popupMaxHeight} {paperProps}>
120
+ <Popper
121
+ fullWidth
122
+ {open}
123
+ {onClickOutside}
124
+ {...popperProps}
125
+ {popupMaxHeight}
126
+ {popupPositionX}
127
+ {popupPositionY}
128
+ {paperProps}
129
+ {lockPoistions}
130
+ {popperHeightForVerticalPosition}
131
+ >
179
132
  <div
180
133
  class:outline
181
134
  class:disabled
@@ -198,6 +151,12 @@ $effect(() => {
198
151
  {before}
199
152
  {after}
200
153
  >
154
+ {#if dropdownArrowPosition === 'before'}
155
+ <div class:before class:open class="DropdownArrow">
156
+ {@render selectDropdownArrowIcon()}
157
+ </div>
158
+ {/if}
159
+
201
160
  <DynamicInput
202
161
  type="text"
203
162
  {name}
@@ -211,6 +170,9 @@ $effect(() => {
211
170
  {onpaste}
212
171
  {oncopy}
213
172
  {oncut}
173
+ {onkeydown}
174
+ {onkeypress}
175
+ {onkeyup}
214
176
  {placeholder}
215
177
  value={searchable ? searchTerm : selectedOption?.label}
216
178
  {readonly}
@@ -232,43 +194,50 @@ $effect(() => {
232
194
  </UtilityButton>
233
195
  </div>
234
196
  {/if}
197
+
198
+ {#if dropdownArrowPosition === 'after'}
199
+ <div class:after class:open class="DropdownArrow">
200
+ {@render selectDropdownArrowIcon()}
201
+ </div>
202
+ {/if}
235
203
  </InputEnclosure>
236
204
  </div>
237
205
 
238
206
  {#snippet popupChildren()}
239
207
  {#if customPopupContentTyped}
240
- {@render customPopupContentTyped(options, selectedOption)}
208
+ {@render customPopupContentTyped(optionsRaw, selectedOption, onselectMod)}
241
209
  {:else}
242
- <Menu bind:ref={menuRef} {...menuProps}>
243
- {#if options.length}
244
- {#each options as option (option.value)}
245
- <MenuItem
246
- onclick={() => onselectMod(option)}
247
- type="button"
248
- disabled={option.disabled}
249
- selected={selectedOption?.value === option.value}
250
- {...menuItemProps}
251
- >
252
- {#if customMenuItemContentTyped}
253
- {@render customMenuItemContentTyped(
254
- option,
255
- selectedOption?.value === option.value,
256
- )}
257
- {:else}
258
- {option.label}
259
- {/if}
260
- </MenuItem>
261
- {/each}
262
- {:else}
263
- <MenuItem type="text" disabled={true} {...menuItemProps}>
264
- {#if customPlaceholderMenuItemContentTyped}
265
- {@render customPlaceholderMenuItemContentTyped()}
266
- {:else}
267
- {optionsPlaceholder}
268
- {/if}
269
- </MenuItem>
270
- {/if}
271
- </Menu>
210
+ <DynamicMenu
211
+ bind:ref={menuRef}
212
+ {menuItemProps}
213
+ {options}
214
+ keyboardNavigation
215
+ onEnter={onKeyBoardEnter}
216
+ selectedOption={options.find((item) => item.meta?.value === selectedOption?.value)}
217
+ onclick={(_e, option: DynamicMenuItemOption) => onselectMod(option.meta as SelectOption)}
218
+ showOptionsPlaceholder
219
+ {...menuProps}
220
+ >
221
+ {#snippet customMenuItemContent(option, selectedOption)}
222
+ {#if customMenuItemContentTyped}
223
+ {@render customMenuItemContentTyped(
224
+ option?.meta as SelectOption,
225
+ (selectedOption?.meta as SelectOption).value ===
226
+ (option?.meta as SelectOption).value,
227
+ )}
228
+ {:else}
229
+ {(option?.meta as SelectOption).label}
230
+ {/if}
231
+ {/snippet}
232
+
233
+ {#snippet customPlaceholderMenuItemContent()}
234
+ {#if customPlaceholderMenuItemContentTyped}
235
+ {@render customPlaceholderMenuItemContentTyped()}
236
+ {:else}
237
+ {optionsPlaceholder}
238
+ {/if}
239
+ {/snippet}
240
+ </DynamicMenu>
272
241
  {/if}
273
242
  {/snippet}
274
243
  </Popper>
@@ -277,9 +246,27 @@ $effect(() => {
277
246
  <style>.dodo-ui-Select .Select.size--normal .SelectClear.after {
278
247
  margin-right: calc(var(--dodo-ui-space-small) * 2);
279
248
  }
249
+ .dodo-ui-Select .Select.size--normal .DropdownArrow.after {
250
+ margin-right: calc(var(--dodo-ui-space-small) * 2);
251
+ }
252
+ .dodo-ui-Select .Select.size--normal .DropdownArrow.before {
253
+ margin-right: calc(var(--dodo-ui-space-small) * 2);
254
+ }
280
255
  .dodo-ui-Select .Select.size--small .SelectClear.after {
281
256
  margin-right: var(--dodo-ui-space);
282
257
  }
258
+ .dodo-ui-Select .Select.size--small .DropdownArrow.after {
259
+ margin-right: var(--dodo-ui-space);
260
+ }
261
+ .dodo-ui-Select .Select.size--small .DropdownArrow.before {
262
+ margin-right: var(--dodo-ui-space);
263
+ }
283
264
  .dodo-ui-Select .Select.size--large .SelectClear.after {
284
265
  margin-right: calc(var(--dodo-ui-space) * 2);
266
+ }
267
+ .dodo-ui-Select .Select.size--large .DropdownArrow.after {
268
+ margin-right: calc(var(--dodo-ui-space) * 2);
269
+ }
270
+ .dodo-ui-Select .Select.size--large .DropdownArrow.before {
271
+ margin-right: calc(var(--dodo-ui-space) * 2);
285
272
  }</style>
@@ -1,12 +1,13 @@
1
1
  import type { ComponentSize } from '../../../../types/size.js';
2
2
  import type { ComponentRoundness } from '../../../../types/roundness.js';
3
3
  import type { Snippet } from 'svelte';
4
- import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler, MouseEventHandler } from 'svelte/elements';
4
+ import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler, KeyboardEventHandler, MouseEventHandler } from 'svelte/elements';
5
5
  export type SelectOption = {
6
6
  value: string | number | boolean | null | undefined;
7
7
  label: string;
8
8
  disabled?: boolean;
9
9
  };
10
+ export type SelectDropdownArrowPosition = false | 'before' | 'after';
10
11
  export interface SelectProps {
11
12
  /** How large should the button be? */
12
13
  size?: ComponentSize;
@@ -62,12 +63,18 @@ export interface SelectProps {
62
63
  oncopy?: ClipboardEventHandler<HTMLInputElement>;
63
64
  /** oncut event handler */
64
65
  oncut?: ClipboardEventHandler<HTMLInputElement>;
66
+ /** onkeydown event handler */
67
+ onkeydown?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
68
+ /** onkeypress event handler */
69
+ onkeypress?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
70
+ /** onkeyup event handler */
71
+ onkeyup?: KeyboardEventHandler<HTMLInputElement | HTMLButtonElement>;
65
72
  /** custom Content Formatting for variant button */
66
73
  customInputContent?: (val: SelectOption) => Snippet;
67
74
  /** custom Content Formatting for variant button */
68
75
  customMenuItemContent?: (val: SelectOption, selected: boolean) => Snippet;
69
76
  /** Custom Popup Content */
70
- customPopupContent?: (options: SelectOption[], selectedOption: SelectOption) => Snippet;
77
+ customPopupContent?: (options: SelectOption[], selectedOption: SelectOption, onselect: (val: SelectOption) => void) => Snippet;
71
78
  /** custom Content Formatting for variant button */
72
79
  customPlaceholderMenuItemContent?: () => Snippet;
73
80
  /** PopperPopup Max height. Use css compatible value */
@@ -80,8 +87,20 @@ export interface SelectProps {
80
87
  menuProps?: Partial<MenuProps>;
81
88
  /** MenuItem: Menu component props */
82
89
  menuItemProps?: Partial<MenuItemProps>;
90
+ /** Dropdown Arrow Icon */
91
+ customDropdownArrowIcon?: (open: boolean) => Snippet;
92
+ /** Select Dropdown Arrow Position */
93
+ dropdownArrowPosition?: SelectDropdownArrowPosition;
94
+ /** Popup stick horizontally */
95
+ popupPositionX?: PositionX;
96
+ /** Popup stick vertically */
97
+ popupPositionY?: PositionY;
98
+ /** Lock positions, disable auto top, bottom position based */
99
+ lockPoistions?: boolean;
100
+ /** Popper Height For Vertical Position, default 300 */
101
+ popperHeightForVerticalPosition?: number;
83
102
  }
84
- import { type MenuItemProps, type MenuProps, type PaperProps, type PopperProps } from '../../../../index.js';
103
+ import { type MenuItemProps, type MenuProps, type PaperProps, type PopperProps, type PositionX, type PositionY } from '../../../../index.js';
85
104
  declare const Select: import("svelte").Component<SelectProps, {}, "ref">;
86
105
  type Select = ReturnType<typeof Select>;
87
106
  export default Select;
@@ -90,3 +90,30 @@ const { Story } = defineMeta({
90
90
  },
91
91
  }}
92
92
  />
93
+
94
+ <Story
95
+ name="KeyDown"
96
+ args={{
97
+ onkeydown: (e: TextInputKeyboardEvent) => {
98
+ console.log('onkeydown Event', e.key);
99
+ },
100
+ }}
101
+ />
102
+
103
+ <Story
104
+ name="KeyPress"
105
+ args={{
106
+ onkeypress: (e: TextInputKeyboardEvent) => {
107
+ console.log('onkeypress Event', e.key);
108
+ },
109
+ }}
110
+ />
111
+
112
+ <Story
113
+ name="KeyUp"
114
+ args={{
115
+ onkeyup: (e: TextInputKeyboardEvent) => {
116
+ console.log('onkeyup Event', e.key);
117
+ },
118
+ }}
119
+ />
@@ -10,18 +10,16 @@
10
10
 
11
11
  <script lang="ts">import InputEnclosure from '../../../developer tools/components/InputEnclosure/InputEnclosure.svelte';
12
12
  import DynamicInput, {} from '../../../developer tools/components/DynamicInput/DynamicInput.svelte';
13
- let { type = 'text', size = 'normal', roundness = 1, outline = true, name, id, class: className = '', disabled = false, oninput, onchange, onblur, onfocus, onpaste, oncopy, oncut, before, after, error = false, value = $bindable(), placeholder, ref = $bindable(), readonly = false, } = $props();
13
+ let { type = 'text', size = 'normal', roundness = 1, outline = true, name, id, class: className = '', disabled = false, oninput, onchange, onblur, onfocus, onpaste, oncopy, oncut, onkeydown, onkeypress, onkeyup, before, after, error = false, value = $bindable(), placeholder, ref = $bindable(), readonly = false, } = $props();
14
14
  let focused = $state(false);
15
15
  function onfocusMod(e) {
16
16
  const eTyped = e;
17
- focused = true;
18
17
  if (onfocus) {
19
18
  onfocus(eTyped);
20
19
  }
21
20
  }
22
21
  function onblurMod(e) {
23
22
  const eTyped = e;
24
- focused = false;
25
23
  if (onblur) {
26
24
  onblur(eTyped);
27
25
  }
@@ -42,6 +40,7 @@ function onblurMod(e) {
42
40
  {id}
43
41
  {disabled}
44
42
  bind:ref
43
+ bind:focused
45
44
  {oninput}
46
45
  {onchange}
47
46
  onfocus={onfocusMod}
@@ -49,6 +48,9 @@ function onblurMod(e) {
49
48
  {onpaste}
50
49
  {oncopy}
51
50
  {oncut}
51
+ onkeydown={onkeydown ? (e) => onkeydown(e as TextInputKeyboardEvent) : undefined}
52
+ onkeypress={onkeypress ? (e) => onkeypress(e as TextInputKeyboardEvent) : undefined}
53
+ onkeyup={onkeyup ? (e) => onkeyup(e as TextInputKeyboardEvent) : undefined}
52
54
  {placeholder}
53
55
  bind:value
54
56
  {readonly}
@@ -1,7 +1,7 @@
1
1
  import type { ComponentRoundness } from '../../../../types/roundness.js';
2
2
  import type { ComponentSize } from '../../../../types/size.js';
3
3
  import type { Snippet } from 'svelte';
4
- import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler } from 'svelte/elements';
4
+ import type { ChangeEventHandler, ClipboardEventHandler, FocusEventHandler, FormEventHandler, KeyboardEventHandler } from 'svelte/elements';
5
5
  export type TextInputType = 'text' | 'tel' | 'email' | 'password' | 'url' | 'number';
6
6
  export declare const textInputTypeArray: TextInputType[];
7
7
  export type TextInputFocusEvent = FocusEvent & {
@@ -13,6 +13,9 @@ export type TextInputClipboardEvent = ClipboardEvent & {
13
13
  export type TextInputInputEvent = Event & {
14
14
  currentTarget: EventTarget & HTMLInputElement;
15
15
  };
16
+ export type TextInputKeyboardEvent = KeyboardEvent & {
17
+ currentTarget: EventTarget & HTMLInputElement;
18
+ };
16
19
  export interface TextInputProps {
17
20
  /** Input type? */
18
21
  type?: TextInputType;
@@ -58,6 +61,12 @@ export interface TextInputProps {
58
61
  oncopy?: ClipboardEventHandler<HTMLInputElement>;
59
62
  /** oncut event handler */
60
63
  oncut?: ClipboardEventHandler<HTMLInputElement>;
64
+ /** onkeydown event handler */
65
+ onkeydown?: KeyboardEventHandler<HTMLInputElement>;
66
+ /** onkeypress event handler */
67
+ onkeypress?: KeyboardEventHandler<HTMLInputElement>;
68
+ /** onkeyup event handler */
69
+ onkeyup?: KeyboardEventHandler<HTMLInputElement>;
61
70
  }
62
71
  declare const TextInput: import("svelte").Component<TextInputProps, {}, "ref" | "value">;
63
72
  type TextInput = ReturnType<typeof TextInput>;
@@ -0,0 +1,28 @@
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
+ <!-- Custom Menu Item Content -->
13
+ <Story name="CustomMenuItemContent" asChild>
14
+ <DynamicMenu options={dynamicMenuItemOptions}>
15
+ {#snippet customMenuItemContent(option, selectedOption)}
16
+ {selectedOption?.id === option.id ? '✅' : ''} {option.label} 💯💯💯
17
+ {/snippet}
18
+ </DynamicMenu>
19
+ </Story>
20
+
21
+ <!-- Custom Menu Item Placeholder Content -->
22
+ <Story name="CustomPlaceholderMenuItemContent" asChild>
23
+ <DynamicMenu options={[]} showOptionsPlaceholder>
24
+ {#snippet customPlaceholderMenuItemContent()}
25
+ No dice 💯💯💯
26
+ {/snippet}
27
+ </DynamicMenu>
28
+ </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 Customize: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Customize = InstanceType<typeof Customize>;
18
+ export default Customize;
@@ -0,0 +1,51 @@
1
+ <script module lang="ts">import { defineMeta } from '@storybook/addon-svelte-csf';
2
+ import DynamicMenu, {} from './DynamicMenu.svelte';
3
+ export const storyDynamicMenuArgTypes = {};
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
+ export const dynamicMenuItemOptions = [
11
+ {
12
+ id: '1',
13
+ label: 'One',
14
+ },
15
+ {
16
+ id: '2',
17
+ label: 'Two',
18
+ },
19
+ {
20
+ id: '3',
21
+ label: 'Three',
22
+ },
23
+ {
24
+ id: '4',
25
+ label: 'Four',
26
+ },
27
+ {
28
+ id: '5',
29
+ label: 'Five',
30
+ },
31
+ {
32
+ id: '6',
33
+ disabled: true,
34
+ label: 'Five',
35
+ },
36
+ ];
37
+ </script>
38
+
39
+ <!-- Default DynamicMenu -->
40
+ <Story name="Default" args={{ options: dynamicMenuItemOptions }} />
41
+
42
+ <!-- Selected Option -->
43
+ <Story
44
+ name="SelectedOption"
45
+ args={{ options: dynamicMenuItemOptions, selectedOption: dynamicMenuItemOptions[1] }}
46
+ />
47
+
48
+ <Story
49
+ name="ShowPlaceholder"
50
+ args={{ options: [], showOptionsPlaceholder: true, optionsPlaceholder: 'No content found.' }}
51
+ />
@@ -0,0 +1,22 @@
1
+ import DynamicMenu, { type DynamicMenuItemOption } from './DynamicMenu.svelte';
2
+ import type { StoryBookArgTypes } from '../../../../../storybook-types.js';
3
+ export declare const storyDynamicMenuArgTypes: StoryBookArgTypes;
4
+ export declare const dynamicMenuItemOptions: DynamicMenuItemOption[];
5
+ 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> {
6
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
7
+ $$bindings?: Bindings;
8
+ } & Exports;
9
+ (internal: unknown, props: {
10
+ $$events?: Events;
11
+ $$slots?: Slots;
12
+ }): Exports & {
13
+ $set?: any;
14
+ $on?: any;
15
+ };
16
+ z_$$bindings?: Bindings;
17
+ }
18
+ declare const DynamicMenu: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
19
+ [evt: string]: CustomEvent<any>;
20
+ }, {}, {}, string>;
21
+ type DynamicMenu = InstanceType<typeof DynamicMenu>;
22
+ export default DynamicMenu;