@adobe-commerce/elsie 1.0.0-alpha04071347

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 (340) hide show
  1. package/.elsie.js +21 -0
  2. package/.eslintrc.js +18 -0
  3. package/README.md +52 -0
  4. package/__mocks__/svg.js +11 -0
  5. package/bin/builders/build/index.js +20 -0
  6. package/bin/builders/generate/api/index.js +65 -0
  7. package/bin/builders/generate/api/templates/function.js +9 -0
  8. package/bin/builders/generate/api/templates/index.js +7 -0
  9. package/bin/builders/generate/api/templates/story.js +23 -0
  10. package/bin/builders/generate/api/templates/unit-test.js +15 -0
  11. package/bin/builders/generate/component/index.js +87 -0
  12. package/bin/builders/generate/component/templates/Component.js +43 -0
  13. package/bin/builders/generate/component/templates/css.js +24 -0
  14. package/bin/builders/generate/component/templates/index.js +8 -0
  15. package/bin/builders/generate/component/templates/stories.js +46 -0
  16. package/bin/builders/generate/component/templates/unit-test.js +19 -0
  17. package/bin/builders/generate/config/index.js +54 -0
  18. package/bin/builders/generate/config/templates/elsie.js +29 -0
  19. package/bin/builders/generate/container/index.js +65 -0
  20. package/bin/builders/generate/container/templates/Component.js +18 -0
  21. package/bin/builders/generate/container/templates/index.js +8 -0
  22. package/bin/builders/generate/container/templates/stories.js +34 -0
  23. package/bin/builders/generate/container/templates/unit-test.js +19 -0
  24. package/bin/builders/generate/index.js +283 -0
  25. package/bin/builders/gql/createOrClearDirectory.js +33 -0
  26. package/bin/builders/gql/getSchemaRef.js +25 -0
  27. package/bin/builders/gql/index.js +71 -0
  28. package/bin/builders/lint/index.js +5 -0
  29. package/bin/builders/serve/index.js +44 -0
  30. package/bin/builders/storybook/index.js +5 -0
  31. package/bin/builders/test/index.js +5 -0
  32. package/bin/index.js +26 -0
  33. package/bin/lib/cli.js +8 -0
  34. package/bin/lib/config.js +12 -0
  35. package/bin/lib/log-message.js +11 -0
  36. package/bin/lib/string.js +26 -0
  37. package/bin/lib/validate-typeof.js +28 -0
  38. package/bin/lib/write-file.js +30 -0
  39. package/bin/lib/write-parent-index.js +45 -0
  40. package/config/eslint.js +113 -0
  41. package/config/jest.js +90 -0
  42. package/config/prettier.js +16 -0
  43. package/config/setEnvVars.js +14 -0
  44. package/config/storybook/addon.js +130 -0
  45. package/config/storybook/components/FileTree/FileTree.jsx +192 -0
  46. package/config/storybook/components/FileTree/index.js +10 -0
  47. package/config/storybook/components/Flex/Flex.jsx +21 -0
  48. package/config/storybook/components/Flex/Flex.module.css +29 -0
  49. package/config/storybook/components/Flex/index.js +10 -0
  50. package/config/storybook/components/OptionsTable/OptionsTable.jsx +88 -0
  51. package/config/storybook/components/OptionsTable/OptionsTable.module.css +104 -0
  52. package/config/storybook/components/OptionsTable/index.js +10 -0
  53. package/config/storybook/components/Panel/Panel.module.css +56 -0
  54. package/config/storybook/components/Panel/Panel.tsx +46 -0
  55. package/config/storybook/components/Panel/index.ts +10 -0
  56. package/config/storybook/components/Screenshot/Screenshot.jsx +23 -0
  57. package/config/storybook/components/Screenshot/Screenshot.module.css +28 -0
  58. package/config/storybook/components/Screenshot/index.js +10 -0
  59. package/config/storybook/components/Steps/Steps.jsx +21 -0
  60. package/config/storybook/components/Steps/Steps.module.css +43 -0
  61. package/config/storybook/components/Steps/index.js +10 -0
  62. package/config/storybook/components/StoryWrapper/StoryWrapper.jsx +18 -0
  63. package/config/storybook/components/StoryWrapper/StoryWrapper.module.css +22 -0
  64. package/config/storybook/components/StoryWrapper/index.js +10 -0
  65. package/config/storybook/components/Summary/Summary.jsx +19 -0
  66. package/config/storybook/components/Summary/Summary.module.css +20 -0
  67. package/config/storybook/components/Summary/index.js +10 -0
  68. package/config/storybook/components/Variants/Variants.js +57 -0
  69. package/config/storybook/components/Variants/docs.css +48 -0
  70. package/config/storybook/components/Variants/index.js +10 -0
  71. package/config/storybook/components/video/index.jsx +28 -0
  72. package/config/storybook/manager.js +23 -0
  73. package/config/storybook/preview.jsx +88 -0
  74. package/config/storybook/theming/fonts.css +68 -0
  75. package/config/storybook/theming/logo.svg +19 -0
  76. package/config/storybook/theming/manager.css +63 -0
  77. package/config/storybook/theming/preview.css +93 -0
  78. package/config/storybook/theming/theme.js +61 -0
  79. package/config/tsconfig-base.json +16 -0
  80. package/config/tsconfig-preact.json +15 -0
  81. package/config/vite.mjs +306 -0
  82. package/package.json +113 -0
  83. package/post-release.sh +5 -0
  84. package/src/components/Accordion/Accordion.css +88 -0
  85. package/src/components/Accordion/Accordion.stories.tsx +582 -0
  86. package/src/components/Accordion/Accordion.tsx +177 -0
  87. package/src/components/Accordion/index.ts +11 -0
  88. package/src/components/ActionButton/ActionButton.css +100 -0
  89. package/src/components/ActionButton/ActionButton.stories.tsx +169 -0
  90. package/src/components/ActionButton/ActionButton.tsx +53 -0
  91. package/src/components/ActionButton/index.ts +10 -0
  92. package/src/components/ActionButtonGroup/ActionButtonGroup.css +77 -0
  93. package/src/components/ActionButtonGroup/ActionButtonGroup.stories.tsx +97 -0
  94. package/src/components/ActionButtonGroup/ActionButtonGroup.tsx +91 -0
  95. package/src/components/ActionButtonGroup/index.ts +10 -0
  96. package/src/components/AlertBanner/AlertBanner.css +144 -0
  97. package/src/components/AlertBanner/AlertBanner.stories.tsx +165 -0
  98. package/src/components/AlertBanner/AlertBanner.tsx +90 -0
  99. package/src/components/AlertBanner/index.ts +11 -0
  100. package/src/components/Breadcrumbs/Breadcrumbs.css +60 -0
  101. package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +195 -0
  102. package/src/components/Breadcrumbs/Breadcrumbs.tsx +71 -0
  103. package/src/components/Breadcrumbs/index.ts +11 -0
  104. package/src/components/Button/Button.css +213 -0
  105. package/src/components/Button/Button.mdx +133 -0
  106. package/src/components/Button/Button.stories.tsx +398 -0
  107. package/src/components/Button/Button.tsx +121 -0
  108. package/src/components/Button/index.ts +11 -0
  109. package/src/components/Card/Card.css +34 -0
  110. package/src/components/Card/Card.stories.tsx +76 -0
  111. package/src/components/Card/Card.tsx +34 -0
  112. package/src/components/Card/index.ts +10 -0
  113. package/src/components/CartItem/CartItem.css +509 -0
  114. package/src/components/CartItem/CartItem.stories.tsx +628 -0
  115. package/src/components/CartItem/CartItem.tsx +467 -0
  116. package/src/components/CartItem/CartItemSkeleton.tsx +38 -0
  117. package/src/components/CartItem/index.ts +12 -0
  118. package/src/components/CartList/CartList.css +35 -0
  119. package/src/components/CartList/CartList.stories.tsx +111 -0
  120. package/src/components/CartList/CartList.tsx +40 -0
  121. package/src/components/CartList/index.ts +11 -0
  122. package/src/components/Checkbox/Checkbox.css +255 -0
  123. package/src/components/Checkbox/Checkbox.stories.tsx +290 -0
  124. package/src/components/Checkbox/Checkbox.tsx +138 -0
  125. package/src/components/Checkbox/index.ts +10 -0
  126. package/src/components/ColorSwatch/ColorSwatch.css +132 -0
  127. package/src/components/ColorSwatch/ColorSwatch.stories.tsx +274 -0
  128. package/src/components/ColorSwatch/ColorSwatch.tsx +127 -0
  129. package/src/components/ColorSwatch/index.ts +11 -0
  130. package/src/components/ContentGrid/ContentGrid.css +54 -0
  131. package/src/components/ContentGrid/ContentGrid.stories.tsx +137 -0
  132. package/src/components/ContentGrid/ContentGrid.tsx +57 -0
  133. package/src/components/ContentGrid/index.ts +11 -0
  134. package/src/components/Divider/Divider.css +22 -0
  135. package/src/components/Divider/Divider.stories.tsx +62 -0
  136. package/src/components/Divider/Divider.tsx +33 -0
  137. package/src/components/Divider/index.ts +11 -0
  138. package/src/components/Field/Field.css +83 -0
  139. package/src/components/Field/Field.stories.tsx +238 -0
  140. package/src/components/Field/Field.tsx +84 -0
  141. package/src/components/Field/index.ts +10 -0
  142. package/src/components/Header/Header.css +56 -0
  143. package/src/components/Header/Header.stories.tsx +180 -0
  144. package/src/components/Header/Header.tsx +81 -0
  145. package/src/components/Header/index.ts +11 -0
  146. package/src/components/Icon/Icon.css +26 -0
  147. package/src/components/Icon/Icon.stories.helpers.jsx +21 -0
  148. package/src/components/Icon/Icon.stories.tsx +98 -0
  149. package/src/components/Icon/Icon.tsx +112 -0
  150. package/src/components/Icon/index.ts +10 -0
  151. package/src/components/IllustratedMessage/IllustratedMessage.css +61 -0
  152. package/src/components/IllustratedMessage/IllustratedMessage.stories.tsx +126 -0
  153. package/src/components/IllustratedMessage/IllustratedMessage.tsx +78 -0
  154. package/src/components/IllustratedMessage/index.ts +11 -0
  155. package/src/components/Image/Image.css +52 -0
  156. package/src/components/Image/Image.stories.tsx +89 -0
  157. package/src/components/Image/Image.tsx +66 -0
  158. package/src/components/Image/index.ts +10 -0
  159. package/src/components/ImageSwatch/ImageSwatch.css +154 -0
  160. package/src/components/ImageSwatch/ImageSwatch.stories.tsx +310 -0
  161. package/src/components/ImageSwatch/ImageSwatch.tsx +123 -0
  162. package/src/components/ImageSwatch/index.ts +11 -0
  163. package/src/components/InLineAlert/InLineAlert.css +116 -0
  164. package/src/components/InLineAlert/InLineAlert.stories.tsx +326 -0
  165. package/src/components/InLineAlert/InLineAlert.tsx +128 -0
  166. package/src/components/InLineAlert/index.ts +11 -0
  167. package/src/components/Incrementer/Incrementer.css +165 -0
  168. package/src/components/Incrementer/Incrementer.stories.tsx +172 -0
  169. package/src/components/Incrementer/Incrementer.tsx +192 -0
  170. package/src/components/Incrementer/index.ts +10 -0
  171. package/src/components/Input/Input.css +304 -0
  172. package/src/components/Input/Input.stories.tsx +155 -0
  173. package/src/components/Input/Input.tsx +166 -0
  174. package/src/components/Input/index.ts +11 -0
  175. package/src/components/InputDate/InputDate.css +56 -0
  176. package/src/components/InputDate/InputDate.stories.tsx +117 -0
  177. package/src/components/InputDate/InputDate.tsx +120 -0
  178. package/src/components/InputDate/index.ts +11 -0
  179. package/src/components/InputPassword/InputPassword.css +31 -0
  180. package/src/components/InputPassword/InputPassword.stories.tsx +148 -0
  181. package/src/components/InputPassword/InputPassword.tsx +135 -0
  182. package/src/components/InputPassword/PasswordStatusIndicator/PasswordStatusIndicator.css +31 -0
  183. package/src/components/InputPassword/PasswordStatusIndicator/PasswordStatusIndicator.tsx +96 -0
  184. package/src/components/InputPassword/PasswordStatusIndicator/index.ts +11 -0
  185. package/src/components/InputPassword/index.ts +11 -0
  186. package/src/components/Modal/Modal.css +125 -0
  187. package/src/components/Modal/Modal.stories.tsx +250 -0
  188. package/src/components/Modal/Modal.tsx +157 -0
  189. package/src/components/Modal/index.ts +10 -0
  190. package/src/components/Pagination/Pagination.css +95 -0
  191. package/src/components/Pagination/Pagination.stories.tsx +117 -0
  192. package/src/components/Pagination/Pagination.tsx +149 -0
  193. package/src/components/Pagination/index.ts +11 -0
  194. package/src/components/Picker/Picker.css +220 -0
  195. package/src/components/Picker/Picker.stories.tsx +318 -0
  196. package/src/components/Picker/Picker.tsx +203 -0
  197. package/src/components/Picker/index.ts +10 -0
  198. package/src/components/Price/Price.css +57 -0
  199. package/src/components/Price/Price.stories.tsx +110 -0
  200. package/src/components/Price/Price.tsx +75 -0
  201. package/src/components/Price/index.ts +10 -0
  202. package/src/components/PriceRange/PriceRange.css +66 -0
  203. package/src/components/PriceRange/PriceRange.stories.tsx +240 -0
  204. package/src/components/PriceRange/PriceRange.tsx +248 -0
  205. package/src/components/PriceRange/index.ts +11 -0
  206. package/src/components/ProgressSpinner/ProgressSpinner.css +91 -0
  207. package/src/components/ProgressSpinner/ProgressSpinner.stories.tsx +300 -0
  208. package/src/components/ProgressSpinner/ProgressSpinner.tsx +86 -0
  209. package/src/components/ProgressSpinner/index.ts +11 -0
  210. package/src/components/RadioButton/RadioButton.css +134 -0
  211. package/src/components/RadioButton/RadioButton.stories.tsx +126 -0
  212. package/src/components/RadioButton/RadioButton.tsx +86 -0
  213. package/src/components/RadioButton/index.ts +11 -0
  214. package/src/components/Skeleton/Skeleton.css +145 -0
  215. package/src/components/Skeleton/Skeleton.stories.tsx +265 -0
  216. package/src/components/Skeleton/Skeleton.tsx +133 -0
  217. package/src/components/Skeleton/index.ts +10 -0
  218. package/src/components/Tag/Tag.css +26 -0
  219. package/src/components/Tag/Tag.stories.tsx +103 -0
  220. package/src/components/Tag/Tag.tsx +38 -0
  221. package/src/components/Tag/index.ts +11 -0
  222. package/src/components/TextArea/TextArea.css +140 -0
  223. package/src/components/TextArea/TextArea.stories.tsx +130 -0
  224. package/src/components/TextArea/TextArea.tsx +89 -0
  225. package/src/components/TextArea/index.ts +11 -0
  226. package/src/components/TextSwatch/TextSwatch.css +152 -0
  227. package/src/components/TextSwatch/TextSwatch.stories.tsx +277 -0
  228. package/src/components/TextSwatch/TextSwatch.tsx +131 -0
  229. package/src/components/TextSwatch/index.ts +11 -0
  230. package/src/components/ToggleButton/ToggleButton.css +95 -0
  231. package/src/components/ToggleButton/ToggleButton.stories.tsx +190 -0
  232. package/src/components/ToggleButton/ToggleButton.tsx +75 -0
  233. package/src/components/ToggleButton/index.ts +11 -0
  234. package/src/components/UIProvider/UIProvider.css +140 -0
  235. package/src/components/UIProvider/UIProvider.tsx +61 -0
  236. package/src/components/UIProvider/debugger.css +47 -0
  237. package/src/components/UIProvider/index.ts +10 -0
  238. package/src/components/UIProvider/normalize.css +26 -0
  239. package/src/components/index.ts +49 -0
  240. package/src/docs/API/event-bus.mdx +52 -0
  241. package/src/docs/API/graphql.mdx +214 -0
  242. package/src/docs/API/initializer.mdx +119 -0
  243. package/src/docs/API/render.mdx +125 -0
  244. package/src/docs/Design/colors.mdx +202 -0
  245. package/src/docs/Design/designBlocks.jsx +87 -0
  246. package/src/docs/Design/getTokenData.ts +28 -0
  247. package/src/docs/Design/grid.mdx +365 -0
  248. package/src/docs/Design/overview.mdx +69 -0
  249. package/src/docs/Design/shapes.mdx +100 -0
  250. package/src/docs/Design/spacing.mdx +22 -0
  251. package/src/docs/Design/typography.mdx +126 -0
  252. package/src/docs/Utilities/classList.mdx +52 -0
  253. package/src/docs/Utilities/debounce.mdx +49 -0
  254. package/src/docs/Utilities/deepmerge.mdx +12 -0
  255. package/src/docs/Utilities/getFormErrors.mdx +41 -0
  256. package/src/docs/Utilities/getFormValues.mdx +38 -0
  257. package/src/docs/assets/Banner.png +0 -0
  258. package/src/docs/assets/Colors.png +0 -0
  259. package/src/docs/assets/DropinBanner.png +0 -0
  260. package/src/docs/assets/ShapeStyles.png +0 -0
  261. package/src/docs/assets/Spacing.png +0 -0
  262. package/src/docs/assets/Typography.png +0 -0
  263. package/src/docs/cli-usage.mdx +181 -0
  264. package/src/docs/components/overview.mdx +124 -0
  265. package/src/docs/quick-start.mdx +245 -0
  266. package/src/docs/slots.mdx +211 -0
  267. package/src/docs/welcome.mdx +52 -0
  268. package/src/i18n/en_US.json +146 -0
  269. package/src/i18n/index.ts +26 -0
  270. package/src/icons/Add.svg +9 -0
  271. package/src/icons/AddressBook.svg +3 -0
  272. package/src/icons/Bulk.svg +24 -0
  273. package/src/icons/Burger.svg +5 -0
  274. package/src/icons/Card.svg +7 -0
  275. package/src/icons/Cart.svg +11 -0
  276. package/src/icons/Check.svg +8 -0
  277. package/src/icons/CheckWithCircle.svg +4 -0
  278. package/src/icons/ChevronDown.svg +3 -0
  279. package/src/icons/ChevronRight.svg +8 -0
  280. package/src/icons/ChevronUp.svg +3 -0
  281. package/src/icons/Close.svg +4 -0
  282. package/src/icons/Coupon.svg +3 -0
  283. package/src/icons/Date.svg +4 -0
  284. package/src/icons/Delivery.svg +11 -0
  285. package/src/icons/EmptyBox.svg +3 -0
  286. package/src/icons/Eye.svg +3 -0
  287. package/src/icons/EyeClose.svg +3 -0
  288. package/src/icons/Gift.svg +3 -0
  289. package/src/icons/GiftCard.svg +3 -0
  290. package/src/icons/Heart.svg +3 -0
  291. package/src/icons/HeartFilled.svg +3 -0
  292. package/src/icons/InfoFilled.svg +3 -0
  293. package/src/icons/Locker.svg +11 -0
  294. package/src/icons/Minus.svg +3 -0
  295. package/src/icons/Order.svg +6 -0
  296. package/src/icons/OrderError.svg +15 -0
  297. package/src/icons/OrderSuccess.svg +15 -0
  298. package/src/icons/PaymentError.svg +16 -0
  299. package/src/icons/Placeholder.svg +3 -0
  300. package/src/icons/PlaceholderFilled.svg +4 -0
  301. package/src/icons/Search.svg +9 -0
  302. package/src/icons/SearchFilled.svg +10 -0
  303. package/src/icons/Sort.svg +12 -0
  304. package/src/icons/Star.svg +8 -0
  305. package/src/icons/Trash.svg +7 -0
  306. package/src/icons/User.svg +5 -0
  307. package/src/icons/View.svg +14 -0
  308. package/src/icons/Wallet.svg +6 -0
  309. package/src/icons/Warning.svg +12 -0
  310. package/src/icons/WarningFilled.svg +3 -0
  311. package/src/icons/WarningWithCircle.svg +4 -0
  312. package/src/icons/index.ts +42 -0
  313. package/src/lib/classes.ts +34 -0
  314. package/src/lib/config.ts +24 -0
  315. package/src/lib/debounce.ts +16 -0
  316. package/src/lib/deepmerge.ts +45 -0
  317. package/src/lib/deviceUtils.ts +16 -0
  318. package/src/lib/form-values.ts +31 -0
  319. package/src/lib/i18n.ts +18 -0
  320. package/src/lib/image-params-keymap.ts +36 -0
  321. package/src/lib/index.ts +24 -0
  322. package/src/lib/initializer.ts +134 -0
  323. package/src/lib/is-number.ts +12 -0
  324. package/src/lib/render.tsx +138 -0
  325. package/src/lib/resolve-image.ts +101 -0
  326. package/src/lib/signals.ts +11 -0
  327. package/src/lib/slot.tsx +434 -0
  328. package/src/lib/tests.tsx +47 -0
  329. package/src/lib/types.ts +16 -0
  330. package/src/lib/vcomponent.tsx +42 -0
  331. package/static/assets/images/Card.png +0 -0
  332. package/static/assets/images/example.jpg +0 -0
  333. package/static/assets/images/index.ts +11 -0
  334. package/static/dropin.png +0 -0
  335. package/static/favicon.svg +14 -0
  336. package/storybook-stories.js +21 -0
  337. package/tests/__mocks__/browserMocks.ts +28 -0
  338. package/tests/__mocks__/fileMocks.ts +12 -0
  339. package/tests/__mocks__/styleMock.ts +0 -0
  340. package/types/icons.d.ts +18 -0
@@ -0,0 +1,117 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ // https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
11
+ import type { Meta, StoryObj } from '@storybook/preact';
12
+ import { InputDate, InputDateProps } from '@adobe-commerce/elsie/components/InputDate';
13
+ import { action } from '@storybook/addon-actions';
14
+ import { expect, userEvent, within } from '@storybook/test';
15
+
16
+ export default {
17
+ title: 'Components/InputDate',
18
+ component: InputDate,
19
+ parameters: {
20
+ layout: 'fullscreen', // centered | fullscreen
21
+ a11y: {
22
+ config: {
23
+ rules: [{ id: 'color-contrast', enabled: false }],
24
+ },
25
+ },
26
+ },
27
+ args: {
28
+ name: 'birthdate',
29
+ label: 'Birthdate',
30
+ error: '',
31
+ },
32
+ argTypes: {
33
+ name: {
34
+ control: 'text',
35
+ description: 'Form field identifier.',
36
+ },
37
+ value: {
38
+ control: 'text',
39
+ description: 'Field value.',
40
+ },
41
+ label: {
42
+ control: 'text',
43
+ description: 'Displayed field label.',
44
+ },
45
+ error: {
46
+ control: 'text',
47
+ description: 'Field-specific error messages.',
48
+ },
49
+ onChange: {
50
+ action: 'changed',
51
+ defaultValue: action('onChange'),
52
+ description:
53
+ 'Function called when the value of the input changes. It is used to capture and handle the input data.',
54
+ },
55
+ onBlur: {
56
+ action: 'blurred',
57
+ defaultValue: action('onBlur'),
58
+ description:
59
+ 'Function called when the input loses focus. This can be used to trigger validation or other effects when the user moves away from the input field.',
60
+ },
61
+ },
62
+ } as Meta<InputDateProps>;
63
+
64
+ const Template: StoryObj<InputDateProps> = {
65
+ render: (args) => (
66
+ <div style={{ margin: '40px auto', maxWidth: '1200px' }}>
67
+ <InputDate {...args} />
68
+ </div>
69
+ ),
70
+ };
71
+
72
+ type Story = StoryObj<InputDateProps>;
73
+
74
+ export const Default: Story = {
75
+ ...Template,
76
+ args: {
77
+ label: 'Birthdate',
78
+ },
79
+ play: async ({ canvasElement }) => {
80
+ const canvas = within(canvasElement);
81
+ const dateInput = canvas.getByRole('textbox', { name: /date/i });
82
+ await userEvent.type(dateInput, '2023-07-29');
83
+ expect(dateInput).toHaveValue('2023-07-29');
84
+ },
85
+ };
86
+
87
+ export const WithError: Story = {
88
+ ...Template,
89
+ parameters: {
90
+ layout: 'padded',
91
+ a11y: {
92
+ config: {
93
+ rules: [{ id: 'color-contrast', enabled: false }],
94
+ },
95
+ },
96
+ },
97
+ args: {
98
+ ...Default.args,
99
+ error: 'This field is required',
100
+ },
101
+ };
102
+
103
+ export const CustomValue: Story = {
104
+ ...Template,
105
+ parameters: {
106
+ layout: 'padded',
107
+ a11y: {
108
+ config: {
109
+ rules: [{ id: 'color-contrast', enabled: false }],
110
+ },
111
+ },
112
+ },
113
+ args: {
114
+ ...Default.args,
115
+ value: new Date('2023-07-29'),
116
+ },
117
+ };
@@ -0,0 +1,120 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ import { FunctionComponent } from 'preact';
11
+ import { useRef, useState } from 'preact/hooks';
12
+ import { classes, isIOSMobileDevice } from '@adobe-commerce/elsie/lib';
13
+ import { JSX } from 'preact/compat';
14
+ import { Field, Icon, Input, InputProps } from '@adobe-commerce/elsie/components';
15
+ import { Date } from '@adobe-commerce/elsie/icons';
16
+ import { useText } from '@adobe-commerce/elsie/i18n';
17
+
18
+ import '@adobe-commerce/elsie/components/InputDate/InputDate.css';
19
+ import { useCallback } from 'react';
20
+
21
+ export interface InputDateProps extends Omit<InputProps, 'error' | 'value'> {
22
+ label?: string;
23
+ name?: string;
24
+ error?: string;
25
+ value?: Date;
26
+ }
27
+
28
+ export const InputDate: FunctionComponent<InputDateProps> = ({
29
+ name = '',
30
+ error,
31
+ value,
32
+ label,
33
+ onChange,
34
+ onBlur,
35
+ ...props
36
+ }) => {
37
+ const [internalValue, setInternalValue] = useState(value?.toString() ?? '');
38
+ const iosInputRef = useRef<HTMLInputElement>(null);
39
+ const dictionary = useText({
40
+ picker: 'Dropin.InputDate.picker',
41
+ });
42
+
43
+ const handleOnFocus: JSX.MouseEventHandler<HTMLInputElement> = useCallback(
44
+ (event) => {
45
+ event.currentTarget.setAttribute('type', 'date');
46
+
47
+ if (!isIOSMobileDevice()) return;
48
+
49
+ iosInputRef.current.focus();
50
+ },
51
+ []
52
+ );
53
+
54
+ const handleOnClick: JSX.MouseEventHandler<HTMLButtonElement> = useCallback(
55
+ (event) => {
56
+ const input = event.currentTarget.parentElement?.querySelector('input');
57
+ input?.focus();
58
+ input?.showPicker();
59
+ },
60
+ []
61
+ );
62
+
63
+ const handleOnBlur: JSX.MouseEventHandler<HTMLInputElement> = useCallback(
64
+ (event) => {
65
+ event.currentTarget.setAttribute('type', 'text');
66
+ onBlur?.(event);
67
+ },
68
+ [onBlur]
69
+ );
70
+
71
+ const handleInputChange: JSX.MouseEventHandler<HTMLInputElement> =
72
+ useCallback(
73
+ (event) => {
74
+ setInternalValue(event.target.value);
75
+ onChange?.(event);
76
+ },
77
+ [onChange]
78
+ );
79
+
80
+ return (
81
+ <div className={classes(['dropin-input-date'])}>
82
+ {/* This simple input is needed only for iOS devices to trigger the date picker. */}
83
+ {isIOSMobileDevice() ? (
84
+ <input
85
+ ref={iosInputRef}
86
+ data-testid="inputDateIos"
87
+ className="dropin-input-date__input--ios"
88
+ type="date"
89
+ onChange={handleInputChange}
90
+ />
91
+ ) : null}
92
+ <Field error={error}>
93
+ <Input
94
+ data-testid="input-date"
95
+ error={!!error}
96
+ name={name}
97
+ value={internalValue}
98
+ placeholder={label}
99
+ floatingLabel={label}
100
+ onFocus={handleOnFocus}
101
+ onBlur={handleOnBlur}
102
+ onChange={handleInputChange}
103
+ aria-labelledby={label}
104
+ className="dropin-input-date__input"
105
+ {...props}
106
+ />
107
+ </Field>
108
+
109
+ <button
110
+ type="button"
111
+ data-testid="dropin-input-date__icon"
112
+ className="dropin-input-date__icon"
113
+ aria-label={dictionary.picker}
114
+ onClick={handleOnClick}
115
+ >
116
+ <Icon source={Date} size="24" />
117
+ </button>
118
+ </div>
119
+ );
120
+ };
@@ -0,0 +1,11 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ export * from '@adobe-commerce/elsie/components/InputDate/InputDate';
11
+ export { InputDate as default } from '@adobe-commerce/elsie/components/InputDate/InputDate';
@@ -0,0 +1,31 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ .dropin-input-password {
11
+ position: relative;
12
+ }
13
+
14
+ .dropin-input-password > div:first-child {
15
+ margin-bottom: var(--spacing-small);
16
+ }
17
+
18
+ .dropin-input-password .dropin-input-password__eye-icon {
19
+ position: absolute;
20
+ padding: 0;
21
+ height: 24px;
22
+ top: 17px;
23
+ right: 17px;
24
+ cursor: pointer;
25
+ z-index: 2;
26
+ }
27
+
28
+ .dropin-input-password--error .dropin-input-password__eye-icon {
29
+ right: var(--spacing-xbig);
30
+ transition: all 0.3s ease-in-out;
31
+ }
@@ -0,0 +1,148 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ // https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
11
+ import type { Meta, StoryObj } from '@storybook/preact';
12
+ import {
13
+ InputPassword,
14
+ InputPasswordProps,
15
+ } from '@adobe-commerce/elsie/components/InputPassword';
16
+ import { expect, userEvent, within, fn } from '@storybook/test';
17
+
18
+ const meta: Meta<InputPasswordProps> = {
19
+ title: 'Components/InputPassword',
20
+ component: InputPassword,
21
+ parameters: {
22
+ layout: 'fullscreen', // centered | fullscreen
23
+ a11y: {
24
+ config: {
25
+ rules: [{ id: 'color-contrast', enabled: false }],
26
+ },
27
+ },
28
+ },
29
+ args: {
30
+ name: 'password',
31
+ required: true,
32
+ defaultValue: 'password',
33
+ minLength: 8,
34
+ requiredCharacterClasses: 2,
35
+ hideStatusIndicator: true,
36
+ validateLengthConfig: {
37
+ status: 'success',
38
+ icon: 'success',
39
+ message: 'Strong password',
40
+ },
41
+ },
42
+ argTypes: {
43
+ name: {
44
+ control: 'text',
45
+ description: 'Field identifier, used for form data.',
46
+ },
47
+ placeholder: {
48
+ description: 'placeholder text',
49
+ control: 'text',
50
+ },
51
+ floatingLabel: {
52
+ description: 'enable floating label',
53
+ control: 'text',
54
+ },
55
+ defaultValue: {
56
+ control: 'text',
57
+ description:
58
+ 'The initial value of the password field. This is typically used as a default value or placeholder for the password input field in a form.',
59
+ },
60
+ required: {
61
+ control: 'boolean',
62
+ description: 'Marks field as mandatory.',
63
+ },
64
+ errorMessage: {
65
+ description: 'Sets a custom error message for display in the interface',
66
+ control: 'text',
67
+ },
68
+ className: {
69
+ control: 'text',
70
+ description: 'Custom CSS class name.',
71
+ },
72
+ autoComplete: {
73
+ control: 'text',
74
+ description: 'Enables browser autocomplete.',
75
+ },
76
+ hideStatusIndicator: {
77
+ control: 'boolean',
78
+ description: 'Hides the status indicator.',
79
+ },
80
+ onValue: {
81
+ description: 'Callback function to handle value change',
82
+ type: 'function',
83
+ },
84
+ onBlur: {
85
+ description: 'Callback function to handle blur event',
86
+ type: 'function',
87
+ },
88
+ },
89
+ };
90
+
91
+ export default meta;
92
+
93
+ type Story = StoryObj<InputPasswordProps>;
94
+
95
+ export const Default: Story = {
96
+ parameters: {
97
+ layout: 'centered',
98
+ a11y: {
99
+ config: {
100
+ rules: [{ id: 'color-contrast', enabled: false }],
101
+ },
102
+ },
103
+ },
104
+ args: {
105
+ required: true,
106
+ onBlur: fn(),
107
+ },
108
+ play: async ({ canvasElement }) => {
109
+ const canvas = within(canvasElement);
110
+ const passwordInput = document.querySelector('input') as HTMLElement;
111
+ const toggleButton = document.querySelector(
112
+ '.dropin-input-password__eye-icon'
113
+ ) as HTMLElement;
114
+ expect(passwordInput).toHaveAttribute('type', 'password');
115
+
116
+ await userEvent.click(toggleButton);
117
+ expect(passwordInput).toHaveAttribute('type', 'text');
118
+
119
+ await userEvent.clear(passwordInput);
120
+ await expect(await canvas.findByDisplayValue('')).toBeTruthy();
121
+ await userEvent.type(passwordInput, 'passwordtest');
122
+ await expect(await canvas.findByDisplayValue('passwordtest')).toBeTruthy();
123
+
124
+ await userEvent.clear(passwordInput);
125
+ await expect(await canvas.findByDisplayValue('')).toBeTruthy();
126
+ await userEvent.click(toggleButton);
127
+ expect(passwordInput).toHaveAttribute('type', 'password');
128
+ },
129
+ };
130
+
131
+ export const WithError: Story = {
132
+ parameters: {
133
+ layout: 'centered',
134
+ a11y: {
135
+ config: {
136
+ rules: [{ id: 'color-contrast', enabled: false }],
137
+ },
138
+ },
139
+ },
140
+ render: () => {
141
+ return (
142
+ <InputPassword
143
+ errorMessage={'custom error message'}
144
+ defaultValue={'error'}
145
+ />
146
+ );
147
+ },
148
+ };
@@ -0,0 +1,135 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ import { FunctionComponent } from 'preact';
11
+ import { useCallback, useState } from 'preact/hooks';
12
+ import { classes } from '@adobe-commerce/elsie/lib';
13
+ import { Locker, EyeClose, Eye } from '@adobe-commerce/elsie/icons';
14
+ import { Button, Field, Input, Icon } from '@adobe-commerce/elsie/components';
15
+ import { useText } from '@adobe-commerce/elsie/i18n';
16
+ import {
17
+ PasswordStatusIndicator,
18
+ PasswordStatusIndicatorProps,
19
+ } from './PasswordStatusIndicator';
20
+ import { HTMLAttributes } from 'preact/compat';
21
+
22
+ import '@adobe-commerce/elsie/components/InputPassword/InputPassword.css';
23
+
24
+ export interface InputPasswordProps
25
+ extends PasswordStatusIndicatorProps,
26
+ Omit<HTMLAttributes<HTMLDivElement>, 'minLength'> {
27
+ placeholder?: string;
28
+ floatingLabel?: string;
29
+ defaultValue?: string;
30
+ className?: string;
31
+ name?: string;
32
+ autoComplete?: string;
33
+ errorMessage?: string | undefined;
34
+ required?: boolean;
35
+ hideStatusIndicator?: boolean;
36
+ onValue?: (value: any) => void;
37
+ onBlur?: (event: Event) => void;
38
+ }
39
+
40
+ export const InputPassword: FunctionComponent<InputPasswordProps> = ({
41
+ placeholder,
42
+ floatingLabel,
43
+ children,
44
+ name,
45
+ required,
46
+ className,
47
+ minLength,
48
+ autoComplete,
49
+ defaultValue = '',
50
+ hideStatusIndicator = false,
51
+ uniqueSymbolsStatus,
52
+ validateLengthConfig,
53
+ requiredCharacterClasses,
54
+ errorMessage,
55
+ onValue,
56
+ onBlur,
57
+ ...props
58
+ }) => {
59
+ const translations = useText({
60
+ placeholder: 'Dropin.InputPassword.placeholder',
61
+ floatingLabel: 'Dropin.InputPassword.floatingLabel',
62
+ buttonShowTitle: 'Dropin.InputPassword.buttonShowTitle',
63
+ buttonHideTitle: 'Dropin.InputPassword.buttonHideTitle',
64
+ });
65
+
66
+ const [showPassword, setShowPassword] = useState(false);
67
+
68
+ const toggleShowPassword = useCallback(() => {
69
+ setShowPassword((prevShowPassword) => !prevShowPassword);
70
+ }, []);
71
+
72
+ const title = !showPassword
73
+ ? translations.buttonShowTitle
74
+ : translations.buttonHideTitle;
75
+
76
+ return (
77
+ <div
78
+ data-testid="passwordFieldInput"
79
+ className={classes([
80
+ 'dropin-input-password',
81
+ ['dropin-input-password--error', errorMessage],
82
+ className,
83
+ ])}
84
+ {...props}
85
+ >
86
+ <Field error={errorMessage}>
87
+ <Input
88
+ autoComplete={autoComplete}
89
+ name={name ?? 'password'}
90
+ type={!showPassword ? 'password' : 'text'}
91
+ placeholder={placeholder || translations.placeholder}
92
+ floatingLabel={floatingLabel || translations.floatingLabel}
93
+ aria-label={translations.placeholder}
94
+ aria-required={required || true}
95
+ aria-invalid={!!errorMessage}
96
+ aria-describedby="password-feedback"
97
+ required={required || false}
98
+ value={defaultValue}
99
+ onValue={onValue}
100
+ icon={<Locker />}
101
+ onBlur={onBlur}
102
+ data-testid="passwordInput"
103
+ />
104
+ </Field>
105
+ <Button
106
+ aria-label={title}
107
+ title={title}
108
+ type={'button'}
109
+ data-testid="toggle-password-icon"
110
+ variant="tertiary"
111
+ className={classes([
112
+ 'dropin-input-password__eye-icon',
113
+ `dropin-input-password__eye-icon--${showPassword ? 'show' : 'hide'}`,
114
+ className,
115
+ ])}
116
+ onClick={toggleShowPassword}
117
+ >
118
+ <Icon
119
+ focusable={false}
120
+ aria-hidden={showPassword}
121
+ source={!showPassword ? EyeClose : Eye}
122
+ />
123
+ </Button>
124
+ {hideStatusIndicator ? null : (
125
+ <PasswordStatusIndicator
126
+ minLength={minLength}
127
+ requiredCharacterClasses={requiredCharacterClasses}
128
+ validateLengthConfig={validateLengthConfig}
129
+ uniqueSymbolsStatus={uniqueSymbolsStatus}
130
+ />
131
+ )}
132
+ {children}
133
+ </div>
134
+ );
135
+ };
@@ -0,0 +1,31 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ .dropin-password-status-indicator__item {
11
+ display: grid;
12
+ grid-template-columns: 20px auto;
13
+ align-items: center;
14
+ justify-content: left;
15
+ gap: 0 8px;
16
+
17
+ font: var(--type-details-caption-2-font);
18
+ letter-spacing: var(--type-details-caption-2-letter-spacing);
19
+ }
20
+
21
+ .dropin-password-status-indicator__item--pending {
22
+ color: var(--color-neutral-700, #666);
23
+ }
24
+
25
+ .dropin-password-status-indicator__item--success {
26
+ color: var(--color-positive-800, #53824c);
27
+ }
28
+
29
+ .dropin-password-status-indicator__item--error {
30
+ color: var(--color-alert-800, #bf4545);
31
+ }
@@ -0,0 +1,96 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ import { FunctionComponent, JSX } from 'preact';
11
+ import { HTMLAttributes } from 'preact/compat';
12
+ import { classes } from '@adobe-commerce/elsie/lib';
13
+ import { useText } from '@adobe-commerce/elsie/i18n';
14
+ import {
15
+ Check,
16
+ Close as ErrorValidation,
17
+ Minus as PendingValidation,
18
+ } from '@adobe-commerce/elsie/icons';
19
+
20
+ import '@adobe-commerce/elsie/components/InputPassword/PasswordStatusIndicator/PasswordStatusIndicator.css';
21
+
22
+ type statusTypes = '' | 'success' | 'error' | 'pending';
23
+
24
+ export interface ValidateLengthConfigProps {
25
+ status?: statusTypes;
26
+ icon?: statusTypes;
27
+ message?: string;
28
+ }
29
+
30
+ export interface PasswordStatusIndicatorProps {
31
+ validateLengthConfig?: ValidateLengthConfigProps;
32
+ uniqueSymbolsStatus?: statusTypes;
33
+ minLength?: number;
34
+ requiredCharacterClasses?: number;
35
+ }
36
+
37
+ const getIcon: { [key: string]: JSX.Element } = {
38
+ pending: <PendingValidation />,
39
+ success: <Check />,
40
+ error: <ErrorValidation style={{ fill: 'red' }} />,
41
+ };
42
+
43
+ export const PasswordStatusIndicator: FunctionComponent<
44
+ PasswordStatusIndicatorProps & HTMLAttributes<HTMLDivElement>
45
+ > = ({
46
+ minLength = 0,
47
+ requiredCharacterClasses = 0,
48
+ uniqueSymbolsStatus = 'pending',
49
+ validateLengthConfig = { status: '', icon: '', message: '' },
50
+ }) => {
51
+ const translations = useText({
52
+ chartTwoSymbols: 'Dropin.PasswordStatusIndicator.chartTwoSymbols',
53
+ chartThreeSymbols: 'Dropin.PasswordStatusIndicator.chartThreeSymbols',
54
+ chartFourSymbols: 'Dropin.PasswordStatusIndicator.chartFourSymbols',
55
+ });
56
+
57
+ const getMessage = (chart: number) => {
58
+ switch (chart) {
59
+ case 2:
60
+ return translations.chartTwoSymbols;
61
+ case 3:
62
+ return translations.chartThreeSymbols;
63
+ case 4:
64
+ return translations.chartFourSymbols;
65
+ default:
66
+ return '';
67
+ }
68
+ };
69
+
70
+ return (
71
+ <div className={classes(['dropin-password-status-indicator'])}>
72
+ {minLength > 0 ? (
73
+ <div
74
+ className={`dropin-password-status-indicator__item dropin-password-status-indicator__item--${validateLengthConfig.status}`}
75
+ data-testid={`dropin-password-status-indicator__item--${validateLengthConfig.icon}`}
76
+ >
77
+ {getIcon[validateLengthConfig.icon as string]}
78
+ <span className={`${validateLengthConfig.status}`}>
79
+ {validateLengthConfig.message}
80
+ </span>
81
+ </div>
82
+ ) : null}
83
+ {requiredCharacterClasses >= 2 ? (
84
+ <div
85
+ className={`dropin-password-status-indicator__item dropin-password-status-indicator__item--${uniqueSymbolsStatus}`}
86
+ data-testid={`dropin-password-status-indicator__item--${uniqueSymbolsStatus}`}
87
+ >
88
+ {getIcon[uniqueSymbolsStatus]}
89
+ <span className={`pending`}>
90
+ {getMessage(requiredCharacterClasses)}
91
+ </span>
92
+ </div>
93
+ ) : null}
94
+ </div>
95
+ );
96
+ };