@finsweet/webflow-apps-utils 1.0.2 → 1.0.4

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 (293) hide show
  1. package/README.md +162 -1
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.js +2 -1
  4. package/dist/providers/GlobalProvider.mdx +322 -0
  5. package/dist/providers/GlobalProvider.svelte +58 -0
  6. package/dist/providers/GlobalProvider.svelte.d.ts +4 -0
  7. package/dist/providers/configuratorUtils.d.ts +37 -0
  8. package/dist/providers/configuratorUtils.js +219 -0
  9. package/dist/providers/globalContext.svelte.d.ts +18 -0
  10. package/dist/providers/globalContext.svelte.js +439 -0
  11. package/dist/providers/index.d.ts +5 -0
  12. package/dist/providers/index.js +7 -0
  13. package/dist/providers/types.d.ts +103 -0
  14. package/dist/providers/types.js +6 -0
  15. package/dist/router/Router.mdx +958 -0
  16. package/dist/router/Router.stories.d.ts +6 -0
  17. package/dist/router/Router.stories.js +47 -0
  18. package/dist/router/examples/RouterExample.svelte +271 -0
  19. package/dist/{ui/components/NoSettingsNeeded.svelte.d.ts → router/examples/RouterExample.svelte.d.ts} +3 -3
  20. package/dist/router/examples/index.d.ts +4 -0
  21. package/dist/router/examples/index.js +4 -0
  22. package/dist/router/examples/pages/AboutPage.svelte +568 -0
  23. package/dist/router/examples/pages/AboutPage.svelte.d.ts +13 -0
  24. package/dist/router/examples/pages/HomePage.svelte +200 -0
  25. package/dist/router/examples/pages/HomePage.svelte.d.ts +14 -0
  26. package/dist/router/examples/pages/NotFoundPage.svelte +307 -0
  27. package/dist/router/examples/pages/NotFoundPage.svelte.d.ts +17 -0
  28. package/dist/router/hooks.svelte.d.ts +2 -2
  29. package/dist/router/index.d.ts +3 -0
  30. package/dist/router/index.js +3 -0
  31. package/dist/router/{Link.svelte → providers/Link.svelte} +1 -1
  32. package/dist/router/{Route.svelte → providers/Route.svelte} +1 -1
  33. package/dist/router/{Route.svelte.d.ts → providers/Route.svelte.d.ts} +1 -1
  34. package/dist/router/{Router.svelte → providers/RouterProvider.svelte} +22 -5
  35. package/dist/router/{Router.svelte.d.ts → providers/RouterProvider.svelte.d.ts} +8 -4
  36. package/dist/router/providers/index.d.ts +3 -0
  37. package/dist/router/providers/index.js +3 -0
  38. package/dist/router/{index.svelte.d.ts → router.svelte.d.ts} +1 -3
  39. package/dist/router/{index.svelte.js → router.svelte.js} +1 -4
  40. package/dist/stores/docs/Form.mdx +542 -0
  41. package/dist/stores/forms.d.ts +41 -4
  42. package/dist/stores/forms.js +86 -32
  43. package/dist/stores/index.d.ts +0 -1
  44. package/dist/stores/index.js +0 -1
  45. package/dist/types/customCode.d.ts +1 -1
  46. package/dist/types/webflow.d.ts +31 -47
  47. package/dist/types/window.d.ts +1 -0
  48. package/dist/ui/components/LoadingScreen.svelte +2 -1
  49. package/dist/ui/components/button/Button.svelte +1 -1
  50. package/dist/ui/components/button-group/ButtonGroup.stories.js +112 -0
  51. package/dist/ui/components/{ButtonGroup.svelte → button-group/ButtonGroup.svelte} +20 -33
  52. package/dist/ui/components/button-group/ButtonGroup.svelte.d.ts +13 -0
  53. package/dist/ui/components/button-group/index.d.ts +2 -0
  54. package/dist/ui/components/button-group/index.js +1 -0
  55. package/dist/ui/components/button-group/types.d.ts +32 -0
  56. package/dist/ui/components/checkbox/Checkbox.stories.d.ts +55 -0
  57. package/dist/ui/components/checkbox/Checkbox.stories.js +162 -0
  58. package/dist/ui/components/checkbox/Checkbox.svelte +141 -0
  59. package/dist/ui/components/checkbox/Checkbox.svelte.d.ts +4 -0
  60. package/dist/ui/components/checkbox/index.d.ts +2 -0
  61. package/dist/ui/components/checkbox/index.js +1 -0
  62. package/dist/ui/components/checkbox/types.d.ts +32 -0
  63. package/dist/ui/components/controlled-buttons/ControlledButtons.stories.d.ts +32 -0
  64. package/dist/ui/components/controlled-buttons/ControlledButtons.stories.js +152 -0
  65. package/dist/ui/components/{buttons/FooterButton.svelte → controlled-buttons/ControlledButtons.svelte} +18 -67
  66. package/dist/ui/components/controlled-buttons/ControlledButtons.svelte.d.ts +4 -0
  67. package/dist/ui/components/controlled-buttons/index.d.ts +2 -0
  68. package/dist/ui/components/controlled-buttons/index.js +1 -0
  69. package/dist/ui/components/{buttons → controlled-buttons}/types.d.ts +11 -4
  70. package/dist/ui/components/copy-text/CopyText.stories.d.ts +70 -0
  71. package/dist/ui/components/copy-text/CopyText.stories.js +241 -0
  72. package/dist/ui/components/copy-text/CopyText.svelte +249 -0
  73. package/dist/ui/components/copy-text/CopyText.svelte.d.ts +4 -0
  74. package/dist/ui/components/copy-text/index.d.ts +2 -0
  75. package/dist/ui/components/copy-text/index.js +1 -0
  76. package/dist/ui/components/copy-text/types.d.ts +52 -0
  77. package/dist/ui/components/copy-text/types.js +1 -0
  78. package/dist/ui/components/divider/Divider.stories.svelte +134 -0
  79. package/dist/ui/components/{clickable/Clickable.stories.svelte.d.ts → divider/Divider.stories.svelte.d.ts} +4 -4
  80. package/dist/ui/components/divider/Divider.svelte +30 -0
  81. package/dist/ui/components/divider/Divider.svelte.d.ts +4 -0
  82. package/dist/ui/components/divider/index.d.ts +2 -0
  83. package/dist/ui/components/divider/index.js +1 -0
  84. package/dist/ui/components/divider/types.d.ts +23 -0
  85. package/dist/ui/components/divider/types.js +1 -0
  86. package/dist/ui/components/iframe/Iframe.stories.svelte +122 -0
  87. package/dist/ui/components/{ToggleItem.svelte.d.ts → iframe/Iframe.stories.svelte.d.ts} +7 -8
  88. package/dist/ui/components/iframe/Iframe.svelte +75 -0
  89. package/dist/ui/components/iframe/Iframe.svelte.d.ts +4 -0
  90. package/dist/ui/components/iframe/index.d.ts +2 -0
  91. package/dist/ui/components/iframe/index.js +1 -0
  92. package/dist/ui/components/iframe/types.d.ts +38 -0
  93. package/dist/ui/components/iframe/types.js +1 -0
  94. package/dist/ui/components/index.d.ts +13 -39
  95. package/dist/ui/components/index.js +13 -39
  96. package/dist/ui/components/input/Input.stories.d.ts +33 -0
  97. package/dist/ui/components/input/Input.stories.js +176 -0
  98. package/dist/ui/components/input/Input.svelte +358 -81
  99. package/dist/ui/components/input/types.d.ts +33 -1
  100. package/dist/ui/components/layout/Layout.stories.svelte +3 -3
  101. package/dist/ui/components/layout/Layout.svelte +10 -64
  102. package/dist/ui/components/layout/Layout.svelte.d.ts +2 -2
  103. package/dist/ui/components/layout/common/EditModeMessage.svelte +24 -12
  104. package/dist/ui/components/layout/{ExampleLayout.svelte → examples/ExampleLayout.svelte} +56 -39
  105. package/dist/ui/components/layout/examples/Wrapper.svelte +9 -0
  106. package/dist/ui/components/{Header.svelte.d.ts → layout/examples/Wrapper.svelte.d.ts} +4 -6
  107. package/dist/ui/components/layout/examples/index.d.ts +2 -0
  108. package/dist/ui/components/layout/examples/index.js +2 -0
  109. package/dist/ui/components/layout/index.d.ts +3 -2
  110. package/dist/ui/components/layout/index.js +2 -1
  111. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte +20 -0
  112. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte.d.ts +7 -0
  113. package/dist/ui/components/layout/types.d.ts +1 -10
  114. package/dist/ui/components/modal/Example.svelte +320 -0
  115. package/dist/ui/components/modal/Example.svelte.d.ts +3 -0
  116. package/dist/ui/components/modal/Modal.stories.svelte +18 -0
  117. package/dist/ui/components/modal/Modal.stories.svelte.d.ts +26 -0
  118. package/dist/ui/components/modal/Modal.svelte +490 -0
  119. package/dist/ui/components/modal/Modal.svelte.d.ts +130 -0
  120. package/dist/ui/components/modal/index.d.ts +2 -0
  121. package/dist/ui/components/modal/index.js +1 -0
  122. package/dist/ui/components/modal/types.d.ts +75 -0
  123. package/dist/ui/components/modal/types.js +1 -0
  124. package/dist/ui/components/notification/Notification.stories.svelte +239 -0
  125. package/dist/ui/components/{ToggleList.svelte.d.ts → notification/Notification.stories.svelte.d.ts} +9 -21
  126. package/dist/ui/components/notification/Notification.svelte +294 -0
  127. package/dist/ui/components/notification/Notification.svelte.d.ts +67 -0
  128. package/dist/ui/components/notification/index.d.ts +2 -0
  129. package/dist/ui/components/notification/index.js +1 -0
  130. package/dist/ui/components/notification/types.d.ts +68 -0
  131. package/dist/ui/components/notification/types.js +1 -0
  132. package/dist/ui/components/section/Section.stories.svelte +263 -0
  133. package/dist/ui/components/section/Section.stories.svelte.d.ts +27 -0
  134. package/dist/ui/components/section/Section.svelte +326 -0
  135. package/dist/ui/components/section/Section.svelte.d.ts +5 -0
  136. package/dist/ui/components/section/index.d.ts +2 -0
  137. package/dist/ui/components/section/index.js +1 -0
  138. package/dist/ui/components/section/types.d.ts +114 -0
  139. package/dist/ui/components/section/types.js +1 -0
  140. package/dist/ui/components/{ImageUpload.svelte → shared/ImageUpload.svelte} +3 -3
  141. package/dist/ui/components/{SelectBodyOrDivBlock.svelte → shared/SelectBodyOrDivBlock.svelte} +1 -1
  142. package/dist/ui/components/shared/index.d.ts +2 -0
  143. package/dist/ui/components/shared/index.js +2 -0
  144. package/dist/ui/components/text/Text.stories.svelte +67 -1
  145. package/dist/ui/components/text/Text.svelte +209 -8
  146. package/dist/ui/components/text/types.d.ts +4 -0
  147. package/dist/ui/index.css +33 -5
  148. package/dist/utils/animations/factory.d.ts +7 -0
  149. package/dist/utils/animations/factory.js +101 -0
  150. package/dist/utils/animations/index.d.ts +7 -0
  151. package/dist/utils/animations/index.js +62 -0
  152. package/dist/utils/animations/types.d.ts +39 -0
  153. package/dist/utils/animations/types.js +1 -0
  154. package/dist/utils/api/checkIfAppModeIsDesign.d.ts +1 -2
  155. package/dist/utils/api/checkIfAppModeIsDesign.js +1 -2
  156. package/dist/utils/api/clipboard/handlePaste.d.ts +6 -37
  157. package/dist/utils/api/clipboard/handlePaste.js +2 -6
  158. package/dist/utils/api/getAllAssets.d.ts +1 -2
  159. package/dist/utils/api/getAllAssets.js +1 -2
  160. package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +1 -2
  161. package/dist/utils/api/getFinsweetComponentsEnvironment.js +3 -6
  162. package/dist/utils/api/index.d.ts +0 -1
  163. package/dist/utils/api/index.js +0 -1
  164. package/dist/utils/api/insertWithXSCP.d.ts +1 -2
  165. package/dist/utils/api/insertWithXSCP.js +1 -2
  166. package/dist/utils/auth/crossWindowLogin.d.ts +3 -0
  167. package/dist/utils/auth/crossWindowLogin.js +3 -0
  168. package/dist/utils/auth/index.d.ts +9 -25
  169. package/dist/utils/auth/index.js +9 -25
  170. package/dist/utils/browser-storage/localStorage.d.ts +4 -12
  171. package/dist/utils/browser-storage/localStorage.js +4 -12
  172. package/dist/utils/browser-storage/sessionStorage.d.ts +4 -12
  173. package/dist/utils/browser-storage/sessionStorage.js +4 -12
  174. package/dist/utils/custom-code/api.d.ts +3 -7
  175. package/dist/utils/custom-code/api.js +3 -7
  176. package/dist/utils/custom-code/configs.d.ts +22 -0
  177. package/dist/utils/custom-code/configs.js +40 -0
  178. package/dist/utils/custom-code/index.d.ts +1 -0
  179. package/dist/utils/custom-code/index.js +1 -0
  180. package/dist/utils/helpers/capitalizeFirstLetter.d.ts +4 -0
  181. package/dist/utils/helpers/capitalizeFirstLetter.js +9 -0
  182. package/dist/utils/helpers/cleanupTooltipMessage.d.ts +1 -2
  183. package/dist/utils/helpers/cleanupTooltipMessage.js +1 -2
  184. package/dist/utils/helpers/getTimeNow.d.ts +4 -0
  185. package/dist/utils/helpers/getTimeNow.js +8 -0
  186. package/dist/utils/helpers/goto.d.ts +1 -4
  187. package/dist/utils/helpers/goto.js +2 -7
  188. package/dist/utils/helpers/index.d.ts +5 -0
  189. package/dist/utils/helpers/index.js +5 -0
  190. package/dist/utils/helpers/minifyCode.d.ts +10 -0
  191. package/dist/utils/helpers/minifyCode.js +73 -0
  192. package/dist/utils/helpers/noop.d.ts +1 -1
  193. package/dist/utils/helpers/noop.js +1 -1
  194. package/dist/utils/helpers/numbers.d.ts +4 -14
  195. package/dist/utils/helpers/numbers.js +4 -14
  196. package/dist/utils/helpers/objectsToModuleExports.d.ts +2 -4
  197. package/dist/utils/helpers/objectsToModuleExports.js +2 -3
  198. package/dist/utils/helpers/toHumanReadableList.d.ts +4 -0
  199. package/dist/utils/helpers/toHumanReadableList.js +11 -0
  200. package/dist/utils/helpers/trimText.d.ts +1 -8
  201. package/dist/utils/helpers/trimText.js +1 -8
  202. package/dist/utils/index.d.ts +5 -0
  203. package/dist/utils/index.js +5 -0
  204. package/dist/utils/logger/index.d.ts +0 -2
  205. package/dist/utils/logger/index.js +0 -2
  206. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.d.ts +1 -3
  207. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
  208. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.d.ts +1 -5
  209. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.js +1 -5
  210. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.d.ts +1 -4
  211. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -4
  212. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.d.ts +1 -3
  213. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.js +1 -3
  214. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.d.ts +1 -4
  215. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -4
  216. package/dist/utils/webflow-canvas/attributes/setStyles.d.ts +1 -3
  217. package/dist/utils/webflow-canvas/attributes/setStyles.js +1 -3
  218. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.d.ts +1 -8
  219. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +1 -13
  220. package/dist/utils/webflow-canvas/findInstanceElement.d.ts +0 -6
  221. package/dist/utils/webflow-canvas/findInstanceElement.js +1 -7
  222. package/dist/utils/webflow-canvas/getAllChildren.d.ts +16 -0
  223. package/dist/utils/webflow-canvas/getAllChildren.js +65 -0
  224. package/dist/utils/webflow-canvas/getAllPages.d.ts +3 -10
  225. package/dist/utils/webflow-canvas/getAllPages.js +3 -10
  226. package/dist/utils/webflow-canvas/getElementClassList.d.ts +9 -0
  227. package/dist/utils/webflow-canvas/getElementClassList.js +19 -0
  228. package/dist/utils/webflow-canvas/getSiteStagingUrl.d.ts +1 -4
  229. package/dist/utils/webflow-canvas/getSiteStagingUrl.js +1 -4
  230. package/dist/utils/webflow-canvas/index.d.ts +3 -0
  231. package/dist/utils/webflow-canvas/index.js +3 -0
  232. package/package.json +14 -2
  233. package/dist/router/README.md +0 -397
  234. package/dist/stores/globalStore.d.ts +0 -10
  235. package/dist/stores/globalStore.js +0 -10
  236. package/dist/ui/components/ButtonGroup.svelte.d.ts +0 -28
  237. package/dist/ui/components/Checkbox.svelte +0 -94
  238. package/dist/ui/components/Checkbox.svelte.d.ts +0 -36
  239. package/dist/ui/components/Copy.svelte +0 -329
  240. package/dist/ui/components/Copy.svelte.d.ts +0 -35
  241. package/dist/ui/components/CustomModal.svelte +0 -192
  242. package/dist/ui/components/CustomModal.svelte.d.ts +0 -45
  243. package/dist/ui/components/DisableInEditMode.svelte +0 -66
  244. package/dist/ui/components/DisableInEditMode.svelte.d.ts +0 -33
  245. package/dist/ui/components/Divider.svelte +0 -31
  246. package/dist/ui/components/Divider.svelte.d.ts +0 -31
  247. package/dist/ui/components/Header.svelte +0 -30
  248. package/dist/ui/components/Iframe.svelte +0 -89
  249. package/dist/ui/components/Iframe.svelte.d.ts +0 -40
  250. package/dist/ui/components/InjectComponent.svelte +0 -297
  251. package/dist/ui/components/InjectComponent.svelte.d.ts +0 -27
  252. package/dist/ui/components/Modal.svelte +0 -139
  253. package/dist/ui/components/Modal.svelte.d.ts +0 -42
  254. package/dist/ui/components/Navbar.svelte +0 -132
  255. package/dist/ui/components/Navbar.svelte.d.ts +0 -29
  256. package/dist/ui/components/NoSettingsNeeded.svelte +0 -31
  257. package/dist/ui/components/Notification.svelte +0 -193
  258. package/dist/ui/components/Notification.svelte.d.ts +0 -64
  259. package/dist/ui/components/PlusMinusButton.svelte +0 -91
  260. package/dist/ui/components/PlusMinusButton.svelte.d.ts +0 -22
  261. package/dist/ui/components/PreviewBar.svelte +0 -40
  262. package/dist/ui/components/PreviewBar.svelte.d.ts +0 -20
  263. package/dist/ui/components/ScrollableContent.svelte +0 -18
  264. package/dist/ui/components/ScrollableContent.svelte.d.ts +0 -31
  265. package/dist/ui/components/Section.svelte +0 -97
  266. package/dist/ui/components/Section.svelte.d.ts +0 -50
  267. package/dist/ui/components/Spacer.svelte +0 -9
  268. package/dist/ui/components/Spacer.svelte.d.ts +0 -22
  269. package/dist/ui/components/SpinnerPlusMinus.svelte +0 -75
  270. package/dist/ui/components/SpinnerPlusMinus.svelte.d.ts +0 -23
  271. package/dist/ui/components/SpinnerUpDown.svelte +0 -194
  272. package/dist/ui/components/SpinnerUpDown.svelte.d.ts +0 -31
  273. package/dist/ui/components/Tabs.svelte +0 -71
  274. package/dist/ui/components/Tabs.svelte.d.ts +0 -26
  275. package/dist/ui/components/ToggleItem.svelte +0 -29
  276. package/dist/ui/components/ToggleList.svelte +0 -57
  277. package/dist/ui/components/buttons/FooterButton.svelte.d.ts +0 -10
  278. package/dist/ui/components/buttons/index.d.ts +0 -5
  279. package/dist/ui/components/buttons/index.js +0 -5
  280. package/dist/ui/components/clickable/Clickable.stories.svelte +0 -213
  281. package/dist/ui/components/clickable/Clickable.svelte +0 -93
  282. package/dist/ui/components/clickable/Clickable.svelte.d.ts +0 -4
  283. package/dist/ui/components/clickable/index.d.ts +0 -2
  284. package/dist/ui/components/clickable/index.js +0 -1
  285. package/dist/ui/components/clickable/types.d.ts +0 -17
  286. package/dist/utils/api/copyPaste/index.d.ts +0 -18
  287. /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
  288. /package/dist/ui/components/{buttons → button-group}/types.js +0 -0
  289. /package/dist/ui/components/{clickable → checkbox}/types.js +0 -0
  290. /package/dist/{utils/api/copyPaste/index.js → ui/components/controlled-buttons/types.js} +0 -0
  291. /package/dist/ui/components/layout/{ExampleLayout.svelte.d.ts → examples/ExampleLayout.svelte.d.ts} +0 -0
  292. /package/dist/ui/components/{ImageUpload.svelte.d.ts → shared/ImageUpload.svelte.d.ts} +0 -0
  293. /package/dist/ui/components/{SelectBodyOrDivBlock.svelte.d.ts → shared/SelectBodyOrDivBlock.svelte.d.ts} +0 -0
@@ -69,6 +69,26 @@ const meta = {
69
69
  minLength: {
70
70
  control: 'number',
71
71
  description: 'Minimum input length'
72
+ },
73
+ showSteppers: {
74
+ control: 'boolean',
75
+ description: 'Shows increment/decrement buttons for number inputs (requires type="number")'
76
+ },
77
+ step: {
78
+ control: 'number',
79
+ description: 'Step value for increment/decrement (default: 1)'
80
+ },
81
+ min: {
82
+ control: 'number',
83
+ description: 'Minimum value for number input'
84
+ },
85
+ max: {
86
+ control: 'number',
87
+ description: 'Maximum value for number input'
88
+ },
89
+ debounce: {
90
+ control: 'number',
91
+ description: 'Debounce delay in milliseconds for input events (0 = no debounce)'
72
92
  }
73
93
  }
74
94
  };
@@ -109,6 +129,88 @@ export const NumberInput = {
109
129
  placeholder: 'Enter a number...'
110
130
  }
111
131
  };
132
+ // Stepper functionality
133
+ export const NumberWithSteppers = {
134
+ args: {
135
+ type: 'number',
136
+ showSteppers: true,
137
+ value: '10',
138
+ placeholder: 'Enter a number...'
139
+ }
140
+ };
141
+ export const SteppersWithCustomStep = {
142
+ args: {
143
+ type: 'number',
144
+ showSteppers: true,
145
+ value: '5',
146
+ step: 5,
147
+ placeholder: 'Increments by 5...'
148
+ }
149
+ };
150
+ export const SteppersWithMinMax = {
151
+ args: {
152
+ type: 'number',
153
+ showSteppers: true,
154
+ value: '50',
155
+ min: 0,
156
+ max: 100,
157
+ step: 10,
158
+ placeholder: 'Range: 0-100, Step: 10'
159
+ }
160
+ };
161
+ export const SteppersWithDecimals = {
162
+ args: {
163
+ type: 'number',
164
+ showSteppers: true,
165
+ value: '1.5',
166
+ step: 0.5,
167
+ min: 0,
168
+ max: 10,
169
+ placeholder: 'Decimal steps...'
170
+ }
171
+ };
172
+ export const SteppersAtMinValue = {
173
+ args: {
174
+ type: 'number',
175
+ showSteppers: true,
176
+ value: '0',
177
+ min: 0,
178
+ max: 100,
179
+ step: 1,
180
+ placeholder: 'At minimum value'
181
+ }
182
+ };
183
+ export const SteppersAtMaxValue = {
184
+ args: {
185
+ type: 'number',
186
+ showSteppers: true,
187
+ value: '100',
188
+ min: 0,
189
+ max: 100,
190
+ step: 1,
191
+ placeholder: 'At maximum value'
192
+ }
193
+ };
194
+ export const SteppersDisabled = {
195
+ args: {
196
+ type: 'number',
197
+ showSteppers: true,
198
+ value: '25',
199
+ disabled: true,
200
+ step: 5,
201
+ placeholder: 'Disabled with steppers'
202
+ }
203
+ };
204
+ export const SteppersReadonly = {
205
+ args: {
206
+ type: 'number',
207
+ showSteppers: true,
208
+ value: '75',
209
+ readonly: true,
210
+ step: 5,
211
+ placeholder: 'Readonly with steppers'
212
+ }
213
+ };
112
214
  // States
113
215
  export const Disabled = {
114
216
  args: {
@@ -335,3 +437,77 @@ export const FormFieldExample = {
335
437
  invalid: true
336
438
  }
337
439
  };
440
+ // Debounce examples
441
+ export const WithDebounce = {
442
+ args: {
443
+ placeholder: 'Type fast to see debouncing...',
444
+ debounce: 300,
445
+ oninput: (value) => console.log('Debounced input:', value)
446
+ },
447
+ parameters: {
448
+ docs: {
449
+ description: {
450
+ story: 'Input with 300ms debounce. The oninput event will only fire after you stop typing for 300ms. Check the console to see the difference.'
451
+ }
452
+ }
453
+ }
454
+ };
455
+ export const FastDebounce = {
456
+ args: {
457
+ placeholder: 'Fast debounce (100ms)',
458
+ debounce: 100,
459
+ oninput: (value) => console.log('Fast debounced input:', value)
460
+ },
461
+ parameters: {
462
+ docs: {
463
+ description: {
464
+ story: 'Input with a faster 100ms debounce for more responsive but still controlled input handling.'
465
+ }
466
+ }
467
+ }
468
+ };
469
+ export const SlowDebounce = {
470
+ args: {
471
+ placeholder: 'Slow debounce (1000ms)',
472
+ debounce: 1000,
473
+ oninput: (value) => console.log('Slow debounced input:', value)
474
+ },
475
+ parameters: {
476
+ docs: {
477
+ description: {
478
+ story: 'Input with a slower 1000ms debounce for heavy operations that should only run after the user has finished typing.'
479
+ }
480
+ }
481
+ }
482
+ };
483
+ export const NoDebounce = {
484
+ args: {
485
+ placeholder: 'No debounce (immediate)',
486
+ debounce: 0,
487
+ oninput: (value) => console.log('Immediate input:', value)
488
+ },
489
+ parameters: {
490
+ docs: {
491
+ description: {
492
+ story: 'Input with no debouncing (debounce: 0). Events fire immediately on every keystroke.'
493
+ }
494
+ }
495
+ }
496
+ };
497
+ export const DebounceWithSteppers = {
498
+ args: {
499
+ type: 'number',
500
+ showSteppers: true,
501
+ value: '10',
502
+ debounce: 500,
503
+ placeholder: 'Debounced number input',
504
+ oninput: (value) => console.log('Debounced stepper input:', value)
505
+ },
506
+ parameters: {
507
+ docs: {
508
+ description: {
509
+ story: 'Number input with steppers and debouncing. Both typing and stepper clicks are debounced.'
510
+ }
511
+ }
512
+ }
513
+ };
@@ -2,6 +2,7 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import { onMount } from 'svelte';
4
4
 
5
+ import { ChevronIcon } from '../../icons';
5
6
  import { Text, Tooltip } from '..';
6
7
  import type { InputProps } from './types.js';
7
8
 
@@ -23,33 +24,84 @@
23
24
  type = 'text',
24
25
  alert = null,
25
26
  pill = null,
27
+ showSteppers = false,
28
+ step = 1,
29
+ min = undefined,
30
+ max = undefined,
31
+ debounce = 0,
26
32
  oninput,
27
33
  onblur,
28
34
  onfocus,
29
35
  onkeydown,
36
+ onValueChange,
30
37
  class: className = '',
31
38
  children,
32
39
  ...restProps
33
40
  }: InputProps = $props();
34
41
 
42
+ // Validation: showSteppers can only be used with type="number"
43
+ if (showSteppers && type !== 'number') {
44
+ throw new Error('showSteppers can only be used when type="number"');
45
+ }
46
+
47
+ // Validation: showSteppers and units cannot be used together
48
+ if (showSteppers && units) {
49
+ throw new Error('showSteppers and units cannot be used together');
50
+ }
51
+
35
52
  // Component state using Svelte 5 runes
36
53
  let inputElement: HTMLInputElement | undefined = $state();
37
54
  let pillElement: HTMLSpanElement | undefined = $state();
38
55
  let pillWidth = $state(0);
39
56
 
40
- // Use writable derived for reactive state management
41
- let currInputValue = $derived.by(() => value);
57
+ // Internal reactive state for input value that updates with steppers
58
+ let internalValue = $derived(value);
59
+
60
+ // Track HTML5 validation state
61
+ let isValidationInvalid = $state(false);
62
+
63
+ // Debounce timer for input events
64
+ let debounceTimer: ReturnType<typeof setTimeout> | null = $state(null);
65
+
66
+ // Use internal value for reactive state management
67
+ let currInputValue = $derived(internalValue);
42
68
  let computedColor = $derived(currInputValue ? 'var(--actionPrimaryText)' : 'var(--text3)');
43
69
 
44
70
  let hasPill = $derived(currInputValue && pill);
45
71
  let hasAlert = $derived(alert?.message);
46
72
 
73
+ // Parse numeric value for stepper operations
74
+ let numericValue = $derived.by(() => {
75
+ if (!showSteppers || !currInputValue) return 0;
76
+ const parsed = parseFloat(currInputValue);
77
+ return isNaN(parsed) ? 0 : parsed;
78
+ });
79
+
80
+ // Check if increment/decrement buttons should be disabled
81
+ let canIncrement = $derived.by(() => {
82
+ if (!showSteppers || disabled || readonly) return false;
83
+ if (max !== undefined) return numericValue < max;
84
+ return true;
85
+ });
86
+
87
+ let canDecrement = $derived.by(() => {
88
+ if (!showSteppers || disabled || readonly) return false;
89
+ if (min !== undefined) return numericValue > min;
90
+ return true;
91
+ });
92
+
93
+ // Sync external value prop changes to internal state
94
+ $effect(() => {
95
+ internalValue = value;
96
+ });
97
+
47
98
  let wrapperClasses = $derived(
48
99
  `
49
100
  webflow-input-wrapper
50
101
  ${units ? 'units' : ''}
102
+ ${showSteppers ? 'steppers' : ''}
51
103
  ${disabled ? 'disabled' : ''}
52
- ${invalid || hasAlert ? 'invalid' : ''}
104
+ ${invalid || hasAlert || isValidationInvalid ? 'invalid' : ''}
53
105
  ${className}
54
106
  `
55
107
  .trim()
@@ -134,6 +186,82 @@
134
186
  }
135
187
  });
136
188
 
189
+ /**
190
+ * Updates validation state based on HTML5 input validity
191
+ */
192
+ const updateValidationState = () => {
193
+ if (inputElement && type === 'number') {
194
+ // Check if the input has any validation errors
195
+ isValidationInvalid = !inputElement.validity.valid;
196
+ } else {
197
+ isValidationInvalid = false;
198
+ }
199
+ };
200
+
201
+ // Update validation state when input value changes
202
+ $effect(() => {
203
+ if (inputElement) {
204
+ // Use setTimeout to ensure the input element has been updated
205
+ setTimeout(updateValidationState, 0);
206
+ }
207
+ });
208
+
209
+ // Listen for form reset events to update internal state
210
+ $effect(() => {
211
+ if (inputElement) {
212
+ const form = inputElement.closest('form');
213
+ if (form) {
214
+ const handleFormReset = () => {
215
+ // Use setTimeout to allow the form reset to complete first
216
+ setTimeout(() => {
217
+ if (inputElement) {
218
+ const resetValue = inputElement.value;
219
+ internalValue = resetValue;
220
+ updateValidationState();
221
+ }
222
+ }, 0);
223
+ };
224
+
225
+ form.addEventListener('reset', handleFormReset);
226
+
227
+ return () => {
228
+ form.removeEventListener('reset', handleFormReset);
229
+ };
230
+ }
231
+ }
232
+ });
233
+
234
+ // Cleanup debounce timer on component destruction
235
+ $effect(() => {
236
+ return () => {
237
+ if (debounceTimer) {
238
+ clearTimeout(debounceTimer);
239
+ debounceTimer = null;
240
+ }
241
+ };
242
+ });
243
+
244
+ /**
245
+ * Debounced oninput handler
246
+ */
247
+ const debouncedOninput = (inputValue: string) => {
248
+ if (debounce > 0) {
249
+ // Clear existing timer
250
+ if (debounceTimer) {
251
+ clearTimeout(debounceTimer);
252
+ }
253
+
254
+ // Set new timer
255
+ debounceTimer = setTimeout(() => {
256
+ oninput?.(inputValue);
257
+ debounceTimer = null;
258
+ }, debounce);
259
+ } else {
260
+ // No debouncing, call immediately
261
+ oninput?.(inputValue);
262
+ }
263
+ };
264
+
137
265
  /**
138
266
  * Handles input events
139
267
  */
@@ -141,11 +269,26 @@
141
269
  const target = event.target as HTMLInputElement;
142
270
  const inputValue = target?.value?.trim() || '';
143
271
 
272
+ // Update internal state for reactivity
273
+ internalValue = inputValue;
274
+
144
275
  if (pill) {
145
276
  setTimeout(updatePillPosition, 0);
146
277
  }
147
278
 
148
- oninput?.(inputValue);
279
+ // Call numeric value change handler for any number input when value is numeric
280
+ if (type === 'number' && inputValue) {
281
+ const parsed = parseFloat(inputValue);
282
+ if (!isNaN(parsed)) {
283
+ onValueChange?.(parsed);
284
+ }
285
+ }
286
+
287
+ // Update validation state for real-time feedback
288
+ updateValidationState();
289
+
290
+ // Call debounced oninput handler
291
+ debouncedOninput(inputValue);
149
292
  };
150
293
 
151
294
  /**
@@ -169,9 +312,78 @@
169
312
  * Handles keydown events
170
313
  */
171
314
  const handleKeydown = (event: KeyboardEvent) => {
315
+ // Handle arrow key increments/decrements when steppers are enabled
316
+ if (showSteppers && !disabled && !readonly) {
317
+ if (event.key === 'ArrowUp') {
318
+ event.preventDefault();
319
+ handleIncrement();
320
+ } else if (event.key === 'ArrowDown') {
321
+ event.preventDefault();
322
+ handleDecrement();
323
+ }
324
+ }
325
+
172
326
  onkeydown?.(event);
173
327
  };
174
328
 
329
+ /**
330
+ * Handles increment button click
331
+ */
332
+ const handleIncrement = () => {
333
+ if (!canIncrement) return;
334
+
335
+ const currentNum = numericValue;
336
+ let newValue = currentNum + step;
337
+
338
+ // Apply max constraint
339
+ if (max !== undefined && newValue > max) {
340
+ newValue = max;
341
+ }
342
+
343
+ const newStringValue = newValue.toString();
344
+
345
+ // Update internal state for reactivity
346
+ internalValue = newStringValue;
347
+
348
+ // Update the input element value directly
349
+ if (inputElement) {
350
+ inputElement.value = newStringValue;
351
+ }
352
+
353
+ // Trigger change events
354
+ onValueChange?.(newValue);
355
+ debouncedOninput(newStringValue);
356
+ };
357
+
358
+ /**
359
+ * Handles decrement button click
360
+ */
361
+ const handleDecrement = () => {
362
+ if (!canDecrement) return;
363
+
364
+ const currentNum = numericValue;
365
+ let newValue = currentNum - step;
366
+
367
+ // Apply min constraint
368
+ if (min !== undefined && newValue < min) {
369
+ newValue = min;
370
+ }
371
+
372
+ const newStringValue = newValue.toString();
373
+
374
+ // Update internal state for reactivity
375
+ internalValue = newStringValue;
376
+
377
+ // Update the input element value directly
378
+ if (inputElement) {
379
+ inputElement.value = newStringValue;
380
+ }
381
+
382
+ // Trigger change events
383
+ onValueChange?.(newValue);
384
+ debouncedOninput(newStringValue);
385
+ };
386
+
175
387
  /**
176
388
  * Gets the tooltip background color based on alert type
177
389
  */
@@ -190,6 +402,78 @@
190
402
  };
191
403
  </script>
192
404
 
405
+ {#snippet inputField()}
406
+ <input
407
+ bind:this={inputElement}
408
+ {id}
409
+ class={inputClasses}
410
+ {placeholder}
411
+ {readonly}
412
+ {disabled}
413
+ {type}
414
+ {min}
415
+ {max}
416
+ {step}
417
+ maxlength={maxLength}
418
+ minlength={minLength}
419
+ value={currInputValue}
420
+ defaultValue={value}
421
+ oninput={handleInput}
422
+ onfocus={handleFocus}
423
+ onkeydown={handleKeydown}
424
+ onblur={handleBlur}
425
+ style="font-size: {fontSize}; color: {computedColor};"
426
+ {...restProps}
427
+ />
428
+ {/snippet}
429
+
430
+ {#snippet inputWrapper()}
431
+ <div class={wrapperClasses} style="height: {height}; width: {width};" role="group">
432
+ {#if currInputValue && pill}
433
+ <span
434
+ class="pill"
435
+ class:blue={pill === 'blue'}
436
+ class:gray={pill === 'gray'}
437
+ bind:this={pillElement}
438
+ style="width: {pillWidth}px;"
439
+ ></span>
440
+ {/if}
441
+
442
+ {@render inputField()}
443
+
444
+ {#if units && !showSteppers}
445
+ <div class="input-units-steppers">{units}</div>
446
+ {/if}
447
+
448
+ {#if showSteppers && !units}
449
+ <div class="input-units-steppers steppers">
450
+ <button
451
+ type="button"
452
+ class="stepper-button stepper-up"
453
+ disabled={!canIncrement}
454
+ onclick={handleIncrement}
455
+ aria-label="Increment value"
456
+ >
457
+ <span class="stepper-button-icon">&#8963;</span>
458
+ </button>
459
+ <button
460
+ type="button"
461
+ class="stepper-button stepper-down"
462
+ disabled={!canDecrement}
463
+ onclick={handleDecrement}
464
+ aria-label="Decrement value"
465
+ >
466
+ <span class="stepper-button-icon">&#8963;</span>
467
+ </button>
468
+ </div>
469
+ {/if}
470
+
471
+ {#if children}
472
+ {@render children()}
473
+ {/if}
474
+ </div>
475
+ {/snippet}
476
+
193
477
  {#if hasAlert}
194
478
  <Tooltip
195
479
  message={alert?.message || ''}
@@ -206,85 +490,11 @@
206
490
  class="input-tooltip"
207
491
  >
208
492
  {#snippet target()}
209
- <div class={wrapperClasses} style="height: {height}; width: {width};" role="group">
210
- {#if currInputValue && pill}
211
- <span
212
- class="pill"
213
- class:blue={pill === 'blue'}
214
- class:gray={pill === 'gray'}
215
- bind:this={pillElement}
216
- style="width: {pillWidth}px;"
217
- ></span>
218
- {/if}
219
-
220
- <input
221
- bind:this={inputElement}
222
- {id}
223
- class={inputClasses}
224
- {placeholder}
225
- {readonly}
226
- {disabled}
227
- {type}
228
- maxlength={maxLength}
229
- minlength={minLength}
230
- value={currInputValue}
231
- oninput={handleInput}
232
- onfocus={handleFocus}
233
- onkeydown={handleKeydown}
234
- onblur={handleBlur}
235
- style="font-size: {fontSize}; color: {computedColor};"
236
- {...restProps}
237
- />
238
-
239
- {#if units}
240
- <div class="input-units">{units}</div>
241
- {/if}
242
-
243
- {#if children}
244
- {@render children()}
245
- {/if}
246
- </div>
493
+ {@render inputWrapper()}
247
494
  {/snippet}
248
495
  </Tooltip>
249
496
  {:else}
250
- <div class={wrapperClasses} style="height: {height}; width: {width};" role="group">
251
- {#if currInputValue && pill}
252
- <span
253
- class="pill"
254
- class:blue={pill === 'blue'}
255
- class:gray={pill === 'gray'}
256
- bind:this={pillElement}
257
- style="width: {pillWidth}px;"
258
- ></span>
259
- {/if}
260
-
261
- <input
262
- bind:this={inputElement}
263
- {id}
264
- class={inputClasses}
265
- {placeholder}
266
- {readonly}
267
- {disabled}
268
- {type}
269
- maxlength={maxLength}
270
- minlength={minLength}
271
- value={currInputValue}
272
- oninput={handleInput}
273
- onfocus={handleFocus}
274
- onkeydown={handleKeydown}
275
- onblur={handleBlur}
276
- style="font-size: {fontSize}; color: {computedColor};"
277
- {...restProps}
278
- />
279
-
280
- {#if units}
281
- <div class="input-units">{units}</div>
282
- {/if}
283
-
284
- {#if children}
285
- {@render children()}
286
- {/if}
287
- </div>
497
+ {@render inputWrapper()}
288
498
  {/if}
289
499
 
290
500
  <style>
@@ -324,10 +534,21 @@
324
534
  grid-template-columns: 1fr auto;
325
535
  padding: 0 0 0 4px;
326
536
  }
537
+
538
+ .webflow-input-wrapper.steppers {
539
+ grid-template-columns: 1fr auto;
540
+ padding: 0 0 0 4px;
541
+ }
542
+
327
543
  .webflow-input-wrapper.units .webflow-input {
328
544
  padding-right: 4px;
329
545
  }
330
- .input-units {
546
+
547
+ .webflow-input-wrapper.steppers .webflow-input {
548
+ padding-right: 4px;
549
+ }
550
+
551
+ .input-units-steppers {
331
552
  display: flex;
332
553
  align-items: center;
333
554
  justify-content: center;
@@ -346,6 +567,62 @@
346
567
  text-align: center;
347
568
  opacity: 0.75;
348
569
  }
570
+
571
+ .input-units-steppers.steppers {
572
+ justify-content: center;
573
+ flex-direction: column;
574
+ width: 16px;
575
+ gap: 1px;
576
+ background-color: var(--border1);
577
+ margin-top: -2px;
578
+ margin-bottom: -2px;
579
+ }
580
+
581
+ .stepper-button {
582
+ border: none;
583
+ width: 16px;
584
+ background-color: var(--actionSecondaryBackground);
585
+ color: var(--text2);
586
+ font-size: 0.8em;
587
+ line-height: 1;
588
+ height: 48%;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
592
+ padding: 0;
593
+ cursor: pointer;
594
+ transition: background-color 0.2s ease;
595
+ }
596
+
597
+ .stepper-button-icon {
598
+ width: 8px;
599
+ height: 5px;
600
+ }
601
+
602
+ .stepper-button:hover:not(:disabled) {
603
+ background-color: var(--hoverColor);
604
+ }
605
+
606
+ .stepper-button:disabled {
607
+ opacity: 0.75;
608
+ cursor: not-allowed;
609
+ }
610
+
611
+ .stepper-up {
612
+ transform: rotate(0deg);
613
+ border-radius: 0 1px 0 0;
614
+ }
615
+
616
+ .stepper-down {
617
+ transform: rotate(180deg);
618
+ border-radius: 1px 0 0 0;
619
+ }
620
+
621
+ .stepper-button :global(svg) {
622
+ width: 16px;
623
+ height: 16px;
624
+ }
625
+
349
626
  .webflow-input {
350
627
  padding: 0;
351
628
  margin: 0;