tide-design-system 2.0.22 → 2.0.24

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 (304) hide show
  1. package/.eslintrc.cjs +90 -0
  2. package/.storybook/main.ts +60 -0
  3. package/.storybook/preview.ts +252 -0
  4. package/dist/IconAccountBalance-0a430d19.cjs +2 -0
  5. package/dist/IconAdd-91de604b.cjs +2 -0
  6. package/dist/IconAiDescription-674cca6d.cjs +2 -0
  7. package/dist/IconAlignSpace-7ee811f8.cjs +2 -0
  8. package/dist/IconApplePay-92395240.cjs +2 -0
  9. package/dist/IconArrowBack-3d47d166.cjs +2 -0
  10. package/dist/IconArrowForward-613e128c.cjs +2 -0
  11. package/dist/IconArrowRight-9f39cdbb.cjs +2 -0
  12. package/dist/IconAssignment-915702cc.cjs +2 -0
  13. package/dist/IconAwardStar-447cf4fc.cjs +2 -0
  14. package/dist/IconBookmark-3f6454d9.cjs +2 -0
  15. package/dist/IconCalendarMonth-bb5bbb9b.cjs +2 -0
  16. package/dist/IconCall-08f3119f.cjs +2 -0
  17. package/dist/IconCheck-910929df.cjs +2 -0
  18. package/dist/IconChevronLeft-6626777e.cjs +2 -0
  19. package/dist/IconChevronRight-91bc7ad1.cjs +2 -0
  20. package/dist/IconClear-489c5a46.cjs +2 -0
  21. package/dist/IconClose-538a540f.cjs +2 -0
  22. package/dist/IconCycle-7b7c7325.cjs +2 -0
  23. package/dist/IconDelete-5cc224a1.cjs +2 -0
  24. package/dist/IconDiamond-4e736f5f.cjs +2 -0
  25. package/dist/IconDraft-26850369.cjs +2 -0
  26. package/dist/IconEdit-b4d5f175.cjs +2 -0
  27. package/dist/IconError-4ad48be1.cjs +2 -0
  28. package/dist/IconExpandContent-03a28bfb.cjs +2 -0
  29. package/dist/IconExpandLess-59a80211.cjs +2 -0
  30. package/dist/IconExpandMore-edf55cdd.cjs +2 -0
  31. package/dist/IconFacebook-9c43095a.cjs +2 -0
  32. package/dist/IconFavorite-43091cef.cjs +2 -0
  33. package/dist/IconFavoriteFilled-71277849.cjs +2 -0
  34. package/dist/IconFormatBold-4faa5f99.cjs +2 -0
  35. package/dist/IconFormatItalic-fee490fc.cjs +2 -0
  36. package/dist/IconFormatListBulleted-d0a77d0e.cjs +2 -0
  37. package/dist/IconForum-22217aa0.cjs +2 -0
  38. package/dist/IconGavel-aacae653.cjs +2 -0
  39. package/dist/IconGoogle-77ec192e.cjs +2 -0
  40. package/dist/IconGooglePay-049e93ec.cjs +2 -0
  41. package/dist/IconGrid-1693599f.cjs +2 -0
  42. package/dist/IconHeight-d8ee424f.cjs +2 -0
  43. package/dist/IconHelp-43137a66.cjs +2 -0
  44. package/dist/IconInfo-2d14575c.cjs +2 -0
  45. package/dist/IconInsertText-14c80b9a.cjs +2 -0
  46. package/dist/IconInstagram-43bb02ea.cjs +2 -0
  47. package/dist/IconIosShare-526a016a.cjs +2 -0
  48. package/dist/IconLayout-e663120e.cjs +2 -0
  49. package/dist/IconLinkedIn-088a3792.cjs +2 -0
  50. package/dist/IconLocalShipping-9bca5a95.cjs +2 -0
  51. package/dist/IconLock-1c996287.cjs +2 -0
  52. package/dist/IconMail-f2b8fee4.cjs +2 -0
  53. package/dist/IconMenu-c7c2b143.cjs +2 -0
  54. package/dist/IconMoreHoriz-2c82da62.cjs +2 -0
  55. package/dist/IconNotifications-01f7658b.cjs +2 -0
  56. package/dist/IconOpenInNew-9032f1db.cjs +2 -0
  57. package/dist/IconPalette-269c7286.cjs +2 -0
  58. package/dist/IconPaypal-427e8667.cjs +2 -0
  59. package/dist/IconPerson-ee87961e.cjs +2 -0
  60. package/dist/IconPhotoCamera-56cb060d.cjs +2 -0
  61. package/dist/IconPinterest-87034fbf.cjs +2 -0
  62. package/dist/IconPlayArrow-80f601bf.cjs +2 -0
  63. package/dist/IconRemove-73b05132.cjs +2 -0
  64. package/dist/IconRoundedCorners-53cb2cfc.cjs +2 -0
  65. package/dist/IconRuler-5feb5a83.cjs +2 -0
  66. package/dist/IconSearch-45b2c0e5.cjs +2 -0
  67. package/dist/IconSeating-bc19b98f.cjs +2 -0
  68. package/dist/IconSell-bcede586.cjs +2 -0
  69. package/dist/IconShare-ff50a973.cjs +2 -0
  70. package/dist/IconShoppingCart-eee95744.cjs +2 -0
  71. package/dist/IconSms-0575f458.cjs +2 -0
  72. package/dist/IconStar-e2a88836.cjs +2 -0
  73. package/dist/IconSwapVert-29258e96.cjs +2 -0
  74. package/dist/IconThreeDRotation-7be89ff8.cjs +2 -0
  75. package/dist/IconTrophy-4d05eb75.cjs +2 -0
  76. package/dist/IconTune-1276696d.cjs +2 -0
  77. package/dist/IconTwitter-55b8ba63.cjs +2 -0
  78. package/dist/IconVideocam-f5b07935.cjs +2 -0
  79. package/dist/IconViewInAr-a583aff8.cjs +2 -0
  80. package/dist/IconVisibility-4984bcac.cjs +2 -0
  81. package/dist/IconVolumeOff-35d350ee.cjs +2 -0
  82. package/dist/IconVolumeOn-386ad18b.cjs +2 -0
  83. package/dist/IconWarning-54f3a9ac.cjs +2 -0
  84. package/dist/IconWeight-c6ddd367.cjs +2 -0
  85. package/dist/IconWidth-a556befc.cjs +2 -0
  86. package/dist/IconWidth-c81dbc7a.js +16 -0
  87. package/dist/IconYoutube-ed951c21.cjs +2 -0
  88. package/dist/css/grid-layout.css +6 -2
  89. package/dist/tide-design-system.cjs +2 -0
  90. package/dist/tide-design-system.esm.d.ts +1925 -0
  91. package/dist/tide-design-system.esm.js +2168 -0
  92. package/index.ts +122 -0
  93. package/package.json +8 -12
  94. package/src/assets/css/animation.css +14 -0
  95. package/src/assets/css/dynamic-buttons.css +79 -0
  96. package/src/assets/css/dynamic-utilities.css +39 -0
  97. package/src/assets/css/grid-layout.css +71 -0
  98. package/src/assets/css/main.css +5 -0
  99. package/src/assets/css/realm/aero.css +42 -0
  100. package/src/assets/css/realm/atv.css +43 -0
  101. package/src/assets/css/realm/boatmart.css +42 -0
  102. package/src/assets/css/realm/cycle.css +42 -0
  103. package/src/assets/css/realm/equip.css +42 -0
  104. package/src/assets/css/realm/pwc.css +42 -0
  105. package/src/assets/css/realm/rv.css +50 -0
  106. package/src/assets/css/realm/snow.css +42 -0
  107. package/src/assets/css/realm/truck.css +42 -0
  108. package/src/assets/css/reset.css +79 -0
  109. package/src/assets/css/storybook.css +9 -0
  110. package/src/assets/css/utilities.css +1602 -0
  111. package/src/assets/css/variables.css +118 -0
  112. package/src/assets/svg/icons/IconAccountBalance.svg +5 -0
  113. package/src/assets/svg/icons/IconAdd.svg +3 -0
  114. package/src/assets/svg/icons/IconAiDescription.svg +7 -0
  115. package/src/assets/svg/icons/IconAlignSpace.svg +3 -0
  116. package/src/assets/svg/icons/IconApplePay.svg +5 -0
  117. package/src/assets/svg/icons/IconArrowBack.svg +3 -0
  118. package/src/assets/svg/icons/IconArrowForward.svg +3 -0
  119. package/src/assets/svg/icons/IconArrowRight.svg +3 -0
  120. package/src/assets/svg/icons/IconAssignment.svg +5 -0
  121. package/src/assets/svg/icons/IconAwardStar.svg +5 -0
  122. package/src/assets/svg/icons/IconBookmark.svg +5 -0
  123. package/src/assets/svg/icons/IconCalendarMonth.svg +5 -0
  124. package/src/assets/svg/icons/IconCall.svg +5 -0
  125. package/src/assets/svg/icons/IconCheck.svg +3 -0
  126. package/src/assets/svg/icons/IconChevronLeft.svg +3 -0
  127. package/src/assets/svg/icons/IconChevronRight.svg +3 -0
  128. package/src/assets/svg/icons/IconClear.svg +5 -0
  129. package/src/assets/svg/icons/IconClose.svg +3 -0
  130. package/src/assets/svg/icons/IconCycle.svg +5 -0
  131. package/src/assets/svg/icons/IconDelete.svg +5 -0
  132. package/src/assets/svg/icons/IconDiamond.svg +5 -0
  133. package/src/assets/svg/icons/IconDraft.svg +3 -0
  134. package/src/assets/svg/icons/IconEdit.svg +5 -0
  135. package/src/assets/svg/icons/IconError.svg +5 -0
  136. package/src/assets/svg/icons/IconExpandContent.svg +3 -0
  137. package/src/assets/svg/icons/IconExpandLess.svg +3 -0
  138. package/src/assets/svg/icons/IconExpandMore.svg +3 -0
  139. package/src/assets/svg/icons/IconFacebook.svg +5 -0
  140. package/src/assets/svg/icons/IconFavorite.svg +5 -0
  141. package/src/assets/svg/icons/IconFavoriteFilled.svg +5 -0
  142. package/src/assets/svg/icons/IconFormatBold.svg +5 -0
  143. package/src/assets/svg/icons/IconFormatItalic.svg +3 -0
  144. package/src/assets/svg/icons/IconFormatListBulleted.svg +5 -0
  145. package/src/assets/svg/icons/IconForum.svg +5 -0
  146. package/src/assets/svg/icons/IconGavel.svg +5 -0
  147. package/src/assets/svg/icons/IconGoogle.svg +18 -0
  148. package/src/assets/svg/icons/IconGooglePay.svg +5 -0
  149. package/src/assets/svg/icons/IconGrid.svg +3 -0
  150. package/src/assets/svg/icons/IconHeight.svg +3 -0
  151. package/src/assets/svg/icons/IconHelp.svg +5 -0
  152. package/src/assets/svg/icons/IconInfo.svg +5 -0
  153. package/src/assets/svg/icons/IconInsertText.svg +5 -0
  154. package/src/assets/svg/icons/IconInstagram.svg +5 -0
  155. package/src/assets/svg/icons/IconIosShare.svg +5 -0
  156. package/src/assets/svg/icons/IconLayout.svg +5 -0
  157. package/src/assets/svg/icons/IconLinkedIn.svg +5 -0
  158. package/src/assets/svg/icons/IconLocalShipping.svg +5 -0
  159. package/src/assets/svg/icons/IconLock.svg +5 -0
  160. package/src/assets/svg/icons/IconMail.svg +5 -0
  161. package/src/assets/svg/icons/IconMenu.svg +3 -0
  162. package/src/assets/svg/icons/IconMoreHoriz.svg +5 -0
  163. package/src/assets/svg/icons/IconNotifications.svg +5 -0
  164. package/src/assets/svg/icons/IconOpenInNew.svg +5 -0
  165. package/src/assets/svg/icons/IconPalette.svg +5 -0
  166. package/src/assets/svg/icons/IconPaypal.svg +5 -0
  167. package/src/assets/svg/icons/IconPerson.svg +5 -0
  168. package/src/assets/svg/icons/IconPhotoCamera.svg +5 -0
  169. package/src/assets/svg/icons/IconPinterest.svg +5 -0
  170. package/src/assets/svg/icons/IconPlayArrow.svg +3 -0
  171. package/src/assets/svg/icons/IconRemove.svg +3 -0
  172. package/src/assets/svg/icons/IconRoundedCorners.svg +5 -0
  173. package/src/assets/svg/icons/IconRuler.svg +3 -0
  174. package/src/assets/svg/icons/IconSearch.svg +5 -0
  175. package/src/assets/svg/icons/IconSeating.svg +3 -0
  176. package/src/assets/svg/icons/IconSell.svg +5 -0
  177. package/src/assets/svg/icons/IconShare.svg +5 -0
  178. package/src/assets/svg/icons/IconShoppingCart.svg +5 -0
  179. package/src/assets/svg/icons/IconSms.svg +5 -0
  180. package/src/assets/svg/icons/IconStar.svg +5 -0
  181. package/src/assets/svg/icons/IconSwapVert.svg +5 -0
  182. package/src/assets/svg/icons/IconThreeDRotation.svg +18 -0
  183. package/src/assets/svg/icons/IconTrophy.svg +5 -0
  184. package/src/assets/svg/icons/IconTune.svg +5 -0
  185. package/src/assets/svg/icons/IconTwitter.svg +5 -0
  186. package/src/assets/svg/icons/IconVideocam.svg +5 -0
  187. package/src/assets/svg/icons/IconViewInAr.svg +5 -0
  188. package/src/assets/svg/icons/IconVisibility.svg +5 -0
  189. package/src/assets/svg/icons/IconVolumeOff.svg +5 -0
  190. package/src/assets/svg/icons/IconVolumeOn.svg +5 -0
  191. package/src/assets/svg/icons/IconWarning.svg +5 -0
  192. package/src/assets/svg/icons/IconWeight.svg +3 -0
  193. package/src/assets/svg/icons/IconWidth.svg +3 -0
  194. package/src/assets/svg/icons/IconYoutube.svg +5 -0
  195. package/src/components/TideAccordionItem.vue +105 -0
  196. package/src/components/TideAlert.vue +124 -0
  197. package/src/components/TideBackgroundImage.vue +44 -0
  198. package/src/components/TideBadge.vue +30 -0
  199. package/src/components/TideBadgePremium.vue +31 -0
  200. package/src/components/TideBadgeTrustedPartner.vue +38 -0
  201. package/src/components/TideBreadCrumbs.vue +53 -0
  202. package/src/components/TideButton.vue +67 -0
  203. package/src/components/TideButtonIcon.vue +52 -0
  204. package/src/components/TideButtonPagination.vue +71 -0
  205. package/src/components/TideCard.vue +19 -0
  206. package/src/components/TideCarousel.vue +188 -0
  207. package/src/components/TideChipAction.vue +48 -0
  208. package/src/components/TideChipFilter.vue +55 -0
  209. package/src/components/TideChipInput.vue +44 -0
  210. package/src/components/TideColumns.vue +53 -0
  211. package/src/components/TideDivider.vue +24 -0
  212. package/src/components/TideIcon.vue +58 -0
  213. package/src/components/TideImage.vue +44 -0
  214. package/src/components/TideIndicator.vue +57 -0
  215. package/src/components/TideInputCheckbox.vue +145 -0
  216. package/src/components/TideInputRadio.vue +87 -0
  217. package/src/components/TideInputSelect.vue +204 -0
  218. package/src/components/TideInputText.vue +292 -0
  219. package/src/components/TideInputTextarea.vue +196 -0
  220. package/src/components/TideLink.vue +66 -0
  221. package/src/components/TideModal.vue +187 -0
  222. package/src/components/TidePagination.vue +67 -0
  223. package/src/components/TideSeoLinks.vue +58 -0
  224. package/src/components/TideTabs.vue +89 -0
  225. package/src/components/TideToggle.vue +95 -0
  226. package/src/docs/development.md +51 -0
  227. package/src/docs/integration.md +79 -0
  228. package/src/docs/storybook.md +39 -0
  229. package/src/stories/DemoCssUtilities.stories.ts +154 -0
  230. package/src/stories/DemoCssUtilitiesByTextInput.stories.ts +61 -0
  231. package/src/stories/FoundationsBorder.stories.ts +230 -0
  232. package/src/stories/FoundationsGap.stories.ts +180 -0
  233. package/src/stories/FoundationsMargin.stories.ts +155 -0
  234. package/src/stories/FoundationsPadding.stories.ts +108 -0
  235. package/src/stories/FoundationsShadow.stories.ts +84 -0
  236. package/src/stories/FoundationsTypography.stories.ts +172 -0
  237. package/src/stories/Template.stories.ts +71 -0
  238. package/src/stories/TideAccordionItem.stories.ts +68 -0
  239. package/src/stories/TideAlert.stories.ts +58 -0
  240. package/src/stories/TideBackgroundImage.stories.ts +53 -0
  241. package/src/stories/TideBadge.stories.ts +31 -0
  242. package/src/stories/TideBadgePremium.stories.ts +31 -0
  243. package/src/stories/TideBadgeTrustedPartner.stories.ts +33 -0
  244. package/src/stories/TideBreadCrumbs.stories.ts +43 -0
  245. package/src/stories/TideButton.stories.ts +118 -0
  246. package/src/stories/TideButtonIcon.stories.ts +103 -0
  247. package/src/stories/TideButtonPagination.stories.ts +99 -0
  248. package/src/stories/TideCard.stories.ts +38 -0
  249. package/src/stories/TideCarousel.stories.ts +130 -0
  250. package/src/stories/TideChipAction.stories.ts +46 -0
  251. package/src/stories/TideChipFilter.stories.ts +59 -0
  252. package/src/stories/TideChipInput.stories.ts +42 -0
  253. package/src/stories/TideColumns.stories.ts +90 -0
  254. package/src/stories/TideDivider.stories.ts +46 -0
  255. package/src/stories/TideIcon.stories.ts +29 -0
  256. package/src/stories/TideIndicator.stories.ts +31 -0
  257. package/src/stories/TideInputCheckbox.stories.ts +86 -0
  258. package/src/stories/TideInputRadio.stories.ts +71 -0
  259. package/src/stories/TideInputSelect.stories.ts +145 -0
  260. package/src/stories/TideInputText.stories.ts +181 -0
  261. package/src/stories/TideInputTextarea.stories.ts +116 -0
  262. package/src/stories/TideLink.stories.ts +137 -0
  263. package/src/stories/TideModal.stories.ts +122 -0
  264. package/src/stories/TidePagination.stories.ts +83 -0
  265. package/src/stories/TideSeoLinks.stories.ts +67 -0
  266. package/src/stories/TideTabs.stories.ts +100 -0
  267. package/src/stories/TideToggle.stories.ts +69 -0
  268. package/src/stories/Welcome.mdx +17 -0
  269. package/src/utilities/format.ts +184 -0
  270. package/src/utilities/storybook.ts +295 -0
  271. package/src/utilities/validation.ts +197 -0
  272. package/tests/utilities-format.spec.ts +430 -0
  273. package/tsconfig.app.json +14 -0
  274. package/tsconfig.config.json +12 -0
  275. package/tsconfig.json +22 -0
  276. package/tsconfig.vitest.json +10 -0
  277. package/vite.config.ts +43 -0
  278. package/dist/IconWidth-023f69f2.js +0 -16
  279. package/dist/tide-design-system.js +0 -2168
  280. /package/{dist → src}/types/Alert.ts +0 -0
  281. /package/{dist → src}/types/Badge.ts +0 -0
  282. /package/{dist → src}/types/BreadCrumb.ts +0 -0
  283. /package/{dist → src}/types/Detail.ts +0 -0
  284. /package/{dist → src}/types/Element.ts +0 -0
  285. /package/{dist → src}/types/FacetRange.ts +0 -0
  286. /package/{dist → src}/types/Field.ts +0 -0
  287. /package/{dist → src}/types/Form.ts +0 -0
  288. /package/{dist → src}/types/Formatted.ts +0 -0
  289. /package/{dist → src}/types/Icon.ts +0 -0
  290. /package/{dist → src}/types/Link.ts +0 -0
  291. /package/{dist → src}/types/ListingMedia.ts +0 -0
  292. /package/{dist → src}/types/Orientation.ts +0 -0
  293. /package/{dist → src}/types/Priority.ts +0 -0
  294. /package/{dist → src}/types/Raw.ts +0 -0
  295. /package/{dist → src}/types/Realm.ts +0 -0
  296. /package/{dist → src}/types/RealmConfig.ts +0 -0
  297. /package/{dist → src}/types/Select.ts +0 -0
  298. /package/{dist → src}/types/Size.ts +0 -0
  299. /package/{dist → src}/types/Storybook.ts +0 -0
  300. /package/{dist → src}/types/Styles.ts +0 -0
  301. /package/{dist → src}/types/Tab.ts +0 -0
  302. /package/{dist → src}/types/Target.ts +0 -0
  303. /package/{dist → src}/types/TextInput.ts +0 -0
  304. /package/{dist → src}/types/Validation.ts +0 -0
@@ -0,0 +1,100 @@
1
+ import { action } from '@storybook/addon-actions';
2
+
3
+ import type { Tab } from '@/types/Tab';
4
+
5
+ import TideTabs from '@/components/TideTabs.vue';
6
+ import { change, disabledArgType, doSomething, getLabelsFromOptions, parameters } from '@/utilities/storybook';
7
+
8
+ /* eslint-disable */
9
+ // ^ Storybook controls are based on iterating over object properties instead of array slots (bad form), so these can't be ordered alphabetically.
10
+ const options = {
11
+ 'None': undefined,
12
+ 'Tab 1': 0,
13
+ 'Tab 2': 1,
14
+ 'Tab 3': 2,
15
+ };
16
+ /* eslint-enable */
17
+
18
+ const tabs: Tab[] = [
19
+ {
20
+ dataTrack: 'Tab 0 Click',
21
+ label: 'First Tab',
22
+ },
23
+ {
24
+ dataTrack: 'Tab 1 Click',
25
+ label: 'Second Tab',
26
+ },
27
+ {
28
+ dataTrack: 'Tab 2 Click',
29
+ label: 'Third Tab',
30
+ },
31
+ ];
32
+
33
+ const render = (args: any) => ({
34
+ components: { TideTabs },
35
+ methods: {
36
+ doSomething,
37
+ handleEmit: (event: Event, index: number) => {
38
+ action(`Current tab ${index}`)(event, { index });
39
+
40
+ try {
41
+ const performCallback = eval(args.handleEmit);
42
+
43
+ if (performCallback) {
44
+ performCallback();
45
+ }
46
+ } catch {
47
+ alert('Please specify a valid handler in the "change" control.');
48
+ }
49
+ },
50
+ },
51
+ setup: () => ({ args }),
52
+ template:
53
+ '<TideTabs @change="handleEmit" :key="args.activeTabInitial" class="tide-display-inline-flex" v-bind="args" />',
54
+ });
55
+
56
+ export default {
57
+ argTypes: {
58
+ activeTabInitial: {
59
+ control: {
60
+ labels: getLabelsFromOptions(options),
61
+ type: 'select',
62
+ },
63
+ description: 'Determines which tab should be active by default<br />(Subsequently managed within component)',
64
+ isDynamic: true,
65
+ options: Object.values(options),
66
+ table: {
67
+ defaultValue: { summary: 'None' },
68
+ },
69
+ },
70
+ change: disabledArgType,
71
+ handleEmit: {
72
+ ...change,
73
+ table: {
74
+ defaultValue: { summary: 'None' },
75
+ type: { summary: '(event: Event, tabIndex: number) => void' },
76
+ },
77
+ },
78
+ tabs: {
79
+ control: 'object',
80
+ description: 'Sets label and callback for each tab',
81
+ isCustom: true,
82
+ table: {
83
+ defaultValue: { summary: 'None' },
84
+ type: { summary: 'Tab[]' },
85
+ },
86
+ },
87
+ },
88
+ args: {
89
+ activeTabInitial: undefined,
90
+ handleEmit: 'doSomething',
91
+ tabs,
92
+ },
93
+ component: TideTabs,
94
+ parameters,
95
+ render,
96
+ tags: ['autodocs'],
97
+ title: 'Basic Components/TideTabs',
98
+ };
99
+
100
+ export const Demo = {};
@@ -0,0 +1,69 @@
1
+ import { action } from '@storybook/addon-actions';
2
+
3
+ import TideToggle from '@/components/TideToggle.vue';
4
+ import {
5
+ argTypeBooleanUnrequired,
6
+ change,
7
+ dataTrack,
8
+ disabledArgType,
9
+ doSomething,
10
+ parameters,
11
+ } from '@/utilities/storybook';
12
+
13
+ const render = (args: any, { updateArgs }: any) => ({
14
+ components: { TideToggle },
15
+ methods: {
16
+ doSomething,
17
+ handleEmit: (event: Event, isActive: boolean) => {
18
+ updateArgs({ ...args, isActive });
19
+ action('TideToggle changed')(event, { isActive });
20
+
21
+ try {
22
+ const performCallback = eval(args.handleEmit);
23
+
24
+ if (performCallback) {
25
+ performCallback();
26
+ }
27
+ } catch {
28
+ alert('Please specify a valid handler in the "change" control.');
29
+ }
30
+ },
31
+ },
32
+ setup: () => ({ args }),
33
+ template: `<TideToggle @change="handleEmit" v-bind="args" />`,
34
+ });
35
+
36
+ export default {
37
+ argTypes: {
38
+ change: disabledArgType,
39
+ dataTrack,
40
+ disabled: {
41
+ ...argTypeBooleanUnrequired,
42
+ description: 'Determines clickability',
43
+ },
44
+ handleEmit: {
45
+ ...change,
46
+ table: {
47
+ defaultValue: { summary: 'None' },
48
+ type: { summary: '(event: Event, tabIndex: number) => void' },
49
+ },
50
+ },
51
+ isActive: {
52
+ ...argTypeBooleanUnrequired,
53
+ description: 'Determines whether toggle is active',
54
+ },
55
+ },
56
+ args: {
57
+ dataTrack: '',
58
+ disabled: undefined,
59
+ handleEmit: 'doSomething',
60
+ isActive: undefined,
61
+ },
62
+ component: TideToggle,
63
+ parameters,
64
+ render,
65
+ tags: ['autodocs'],
66
+ title: 'Basic Components/TideToggle',
67
+ };
68
+
69
+ export const Demo = {};
@@ -0,0 +1,17 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Welcome" />
4
+
5
+ # Welcome to TIDE
6
+
7
+ > When building apps, one of the biggest challenges is to figure out if a piece of UI already exists in your codebase and how to use it for the new feature you're building.
8
+ >
9
+ > Storybook catalogues all your components and their use cases. Therefore, you can quickly browse it to find what you're looking for.
10
+ >
11
+ > Here's what the workflow looks like:
12
+ >
13
+ > * Use the sidebar to find the suitable component.
14
+ > * Review its stories to select the variant that fulfills the requirements.
15
+ > * Copy/paste the code snippet into the app and wire it up to data.
16
+
17
+ *(Excerpted from the [Storybook docs](https://storybook.js.org/docs/vue/get-started/browse-stories#use-stories-to-build-uis))*
@@ -0,0 +1,184 @@
1
+ const capitalizeFirst = (string: string) => {
2
+ return string.charAt(0).toUpperCase() + string.slice(1);
3
+ };
4
+
5
+ const formatCamelCase = (input: string): string => {
6
+ return input && typeof input === 'string'
7
+ ? input
8
+ .replace(/^[\s_-]/, '')
9
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
10
+ .replace(/[\s_-]/g, ' ')
11
+ .toLowerCase()
12
+ .split(' ')
13
+ .map((word, index) => (index === 0 ? word : word.slice(0, 1).toUpperCase() + word.slice(1)))
14
+ .join('')
15
+ : input;
16
+ };
17
+
18
+ const formatKebabCase = (input: string): string => {
19
+ return input && typeof input === 'string'
20
+ ? input
21
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
22
+ .toLowerCase()
23
+ .replace(/[\s_-]/g, '-')
24
+ : input;
25
+ };
26
+
27
+ const formatLabel = (value: string) => {
28
+ const labelMap: { [key: string]: string } = {
29
+ false: 'No',
30
+ true: 'Yes',
31
+ };
32
+ return Object.hasOwn(labelMap, value) ? labelMap[value] : value;
33
+ };
34
+
35
+ const formatNumber = (input: number | string): string => {
36
+ let output = input && typeof input === 'number' ? new Intl.NumberFormat().format(input) : String(input || '');
37
+ let digits = output;
38
+
39
+ if (input && typeof input === 'string') {
40
+ digits = digits.replace(/\D/g, '');
41
+ if (Number(digits)) {
42
+ output = new Intl.NumberFormat().format(Number(digits));
43
+ } else {
44
+ output = '0';
45
+ }
46
+ }
47
+
48
+ return output;
49
+ };
50
+
51
+ const formatPascalCase = (input: string): string => {
52
+ return input && typeof input === 'string'
53
+ ? input
54
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
55
+ .replace(/[\s_-]/g, ' ')
56
+ .toLowerCase()
57
+ .split(' ')
58
+ .map((word) => word.slice(0, 1).toUpperCase() + word.slice(1))
59
+ .join('')
60
+ : input;
61
+ };
62
+
63
+ const formatPhone = (input: number | string): string => {
64
+ let output = input && typeof input === 'number' ? String(input) : String(input || '');
65
+ let digits = output;
66
+ digits = digits.replace(/\D/g, '');
67
+
68
+ switch (digits.length) {
69
+ case 7:
70
+ output = `${digits.slice(0, 3)}-${digits.slice(3)}`;
71
+ break;
72
+ case 10:
73
+ output = `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6)}`;
74
+ break;
75
+ case 11:
76
+ output = `${digits.slice(0, 1)}-${digits.slice(1, 4)}-${digits.slice(4, 7)}-${digits.slice(7)}`;
77
+ break;
78
+ default:
79
+ output = digits;
80
+ break;
81
+ }
82
+
83
+ return output;
84
+ };
85
+
86
+ const formatPrice = (input: number | string): string => {
87
+ const output = input ? formatNumber(input) : String(input || '0');
88
+ return `$${output}`;
89
+ };
90
+
91
+ const formatQuotes = (value: string) => {
92
+ if (value.startsWith('"') && value.endsWith('"')) {
93
+ return value.slice(1, -1);
94
+ } else {
95
+ return value;
96
+ }
97
+ };
98
+
99
+ const formatSentenceCase = (input: string): string => {
100
+ let sentenceCase = input;
101
+
102
+ if (input && typeof input === 'string') {
103
+ const lowerCase = input
104
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
105
+ .toLowerCase()
106
+ .replace(/[\s_-]/g, ' ');
107
+
108
+ sentenceCase = lowerCase.slice(0, 1).toUpperCase() + lowerCase.slice(1);
109
+ }
110
+
111
+ return sentenceCase;
112
+ };
113
+
114
+ const formatSnakeCase = (input: string): string => {
115
+ return input && typeof input === 'string'
116
+ ? input
117
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
118
+ .toLowerCase()
119
+ .replace(/[\s_-]/g, '_')
120
+ : input;
121
+ };
122
+
123
+ const formatTitleCase = (input: string): string => {
124
+ return input && typeof input === 'string'
125
+ ? input
126
+ .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
127
+ .toLowerCase()
128
+ .replace(/[\s_-]/g, ' ')
129
+ .split(' ')
130
+ .map((word) => word.slice(0, 1).toUpperCase() + word.slice(1))
131
+ .join(' ')
132
+ : input;
133
+ };
134
+
135
+ const formatUrlFromRoot = (url: string) => {
136
+ const urlFormatted = url.split('.com/');
137
+
138
+ return urlFormatted.length > 1 ? `/${urlFormatted[1]}` : url;
139
+ };
140
+
141
+ const formatWeight = (input: number | string): string => {
142
+ const output = input ? formatNumber(input) : String(input || '0');
143
+ return `${output} lbs`;
144
+ };
145
+
146
+ const getArticle = (noun: string, isPlural = false, isDefinite = false) => {
147
+ const vowels = ['a', 'e', 'i', 'o', 'u'];
148
+ const isVowelLeading = vowels.includes(noun.charAt(0));
149
+
150
+ return isDefinite ? 'the' : isPlural ? 'some' : isVowelLeading ? 'an' : 'a';
151
+ };
152
+
153
+ const priceToNumber = (value: string) => {
154
+ if (Number.isNaN(Number(value))) {
155
+ value = value.replace('$', '');
156
+ value = value.replace(/,/g, '');
157
+ }
158
+ return parseInt(value, 10);
159
+ };
160
+
161
+ const unformatPrice = (input: string): string => {
162
+ const output = input.replace(/\$/g, '').replace(/,/g, '');
163
+ return `${output}`;
164
+ };
165
+
166
+ export {
167
+ capitalizeFirst,
168
+ formatCamelCase,
169
+ formatKebabCase,
170
+ formatLabel,
171
+ formatNumber,
172
+ formatPascalCase,
173
+ formatPhone,
174
+ formatPrice,
175
+ formatQuotes,
176
+ formatSentenceCase,
177
+ formatSnakeCase,
178
+ formatTitleCase,
179
+ formatUrlFromRoot,
180
+ formatWeight,
181
+ getArticle,
182
+ priceToNumber,
183
+ unformatPrice,
184
+ };
@@ -0,0 +1,295 @@
1
+ import type { ArgTypes } from '@storybook/vue3';
2
+
3
+ import { BOOLEAN_UNREQUIRED } from '@/types/Storybook';
4
+ import { CSS } from '@/types/Styles';
5
+ import { ELEMENT, ELEMENT_TEXT_AS_ICON } from '@/types/Element';
6
+
7
+ // Extensible object of key/value pairs
8
+ type KeyValue = { [key: string]: any };
9
+
10
+ // Object with a retrievable key and an extensible object of key/value pairs as the value
11
+ type KeyValueNamed = {
12
+ [key: string]: KeyValue;
13
+ };
14
+
15
+ import type { StoryContext } from '@storybook/vue3';
16
+
17
+ import { formatKebabCase } from '@/utilities/format';
18
+ import { NoneAsEmpty, NoneAsUndefined } from '@/types/Storybook';
19
+
20
+ export const lineBreak = '\r';
21
+ export const tab = ' ';
22
+
23
+ export const argTypeBooleanUnrequired = {
24
+ control: 'select',
25
+ description: 'True, False, or undefined<br />(for demonstration purposes)',
26
+ options: BOOLEAN_UNREQUIRED,
27
+ table: {
28
+ defaultValue: { summary: 'None' },
29
+ type: { summary: 'boolean' },
30
+ },
31
+ };
32
+
33
+ export const argTypeDimension = {
34
+ control: {
35
+ max: 500,
36
+ min: 100,
37
+ step: 100,
38
+ type: 'number',
39
+ },
40
+ table: {
41
+ defaultValue: { summary: 'None' },
42
+ type: { summary: 'number (px)' },
43
+ },
44
+ };
45
+
46
+ export const change = {
47
+ control: 'text',
48
+ description: 'JS code or function to execute on change event',
49
+ isEmit: true,
50
+ name: 'change',
51
+ table: {
52
+ defaultValue: { summary: 'None' },
53
+ type: { summary: '(event: Event) => void' },
54
+ },
55
+ };
56
+
57
+ export const click = {
58
+ control: 'text',
59
+ description: 'JS code or function to execute on click event',
60
+ table: {
61
+ defaultValue: { summary: 'None' },
62
+ type: { summary: '(event: Event) => void' },
63
+ },
64
+ };
65
+
66
+ export const dataTrack = {
67
+ control: 'text',
68
+ description: 'Data attribute for external tracking',
69
+ table: {
70
+ defaultValue: { summary: 'None' },
71
+ type: { summary: 'string' },
72
+ },
73
+ };
74
+
75
+ export const disabledArgType = {
76
+ table: {
77
+ disable: true,
78
+ },
79
+ };
80
+
81
+ export const doSomething = () => {
82
+ alert('Did something.');
83
+ };
84
+
85
+ // Accept a KeyValue as the value of an object with a retrievable key as a Storybook argType.
86
+ export const formatArgType = (collection: KeyValueNamed) => {
87
+ const constant = getKey(collection);
88
+ const keyValues: KeyValue = collection[constant];
89
+
90
+ return {
91
+ constant,
92
+ control: 'select',
93
+ options: {
94
+ ...keyValues,
95
+ },
96
+ table: {
97
+ defaultValue: { summary: 'None' },
98
+ type: { summary: constant },
99
+ },
100
+ };
101
+ };
102
+
103
+ export const formatArgTypeCheck = (collection: KeyValueNamed) => {
104
+ const constant = getKey(collection);
105
+ const keyValues: KeyValue = collection[constant];
106
+
107
+ return {
108
+ constant,
109
+ control: 'check',
110
+ options: {
111
+ ...keyValues,
112
+ },
113
+ table: {
114
+ defaultValue: { summary: 'None' },
115
+ type: { summary: constant },
116
+ },
117
+ };
118
+ };
119
+
120
+ export const formatValueAsConstant = (keyValue: KeyValue, argTypes: ArgTypes) => {
121
+ const [key, value] = Object.entries(keyValue)[0];
122
+ let constant;
123
+
124
+ const arg: ArgTypes = argTypes[key];
125
+
126
+ Object.entries(arg.options).forEach(([optionKey, optionValue]) => {
127
+ if (value === optionValue) {
128
+ constant = `${argTypes[key].constant}.${optionKey}`;
129
+ }
130
+ });
131
+
132
+ return constant;
133
+ };
134
+
135
+ export const formatSnippet = (code: string, context: StoryContext) => {
136
+ const tag = context.component?.__name;
137
+ const { args, argTypes } = context;
138
+
139
+ let classNames: string[] = [];
140
+
141
+ let attributes = Object.entries(args).map((arg: any) => {
142
+ const key = arg[0];
143
+ let value = arg[1];
144
+ const argType: ArgTypes = argTypes[key];
145
+ const conditionKey = argType.if?.arg;
146
+ const conditionValue = argType.if?.eq;
147
+
148
+ // TODO: TypeScript doesn't seem to believe the implict shapes of Storybook's native types?
149
+ const controlType = argType?.control?.type as any;
150
+
151
+ // If arg is conditional, hide when conditional is not met.
152
+ const isClick = key === 'click';
153
+ const isConditionMet = argType.if ? args[conditionKey] === conditionValue : true;
154
+ const isConstant = Object.keys(argTypes).includes(key) && !!argType.constant && controlType === 'select';
155
+ const isConstants = Object.keys(argTypes).includes(key) && !!argType.constant && controlType === 'check';
156
+ const isCustom = argType.isCustom;
157
+ const isDynamic = argType.isDynamic || isConstant || isConstants || typeof value === 'boolean';
158
+ const isEmpty = !isDynamic && value === '';
159
+ const isExcluded = value === undefined || (Array.isArray(value) && !value.length);
160
+ const isEmit = argType.isEmit;
161
+ const isSlot = key === 'default';
162
+
163
+ if (argType.isCss) {
164
+ classNames.push(value);
165
+ }
166
+
167
+ if (isConstant && value !== 'None') {
168
+ const arg: ArgTypes = argType;
169
+
170
+ Object.entries(arg.options).forEach(([optionKey, optionValue]) => {
171
+ if (value === optionValue) {
172
+ value = `${argType.constant}.${optionKey}`;
173
+ }
174
+ });
175
+ }
176
+
177
+ if (isConstants && value.length) {
178
+ const constantSlots: string[] = [];
179
+
180
+ Object.entries(argType.options).forEach(([optionKey, optionValue]) => {
181
+ value.forEach((valueSlot: any) => {
182
+ if (valueSlot === optionValue) {
183
+ constantSlots.push(`${argTypes[key].constant}.${optionKey}`);
184
+ }
185
+ });
186
+ });
187
+
188
+ value = `[${constantSlots.join(', ')}]`;
189
+ }
190
+
191
+ if (isCustom) {
192
+ return `:${formatKebabCase(key)}="${key}"`;
193
+ }
194
+
195
+ if (
196
+ isClick &&
197
+ value &&
198
+ (!args.element || args.element === ELEMENT.BUTTON || args.element === ELEMENT_TEXT_AS_ICON.BUTTON)
199
+ ) {
200
+ return `@click="${value}"`;
201
+ }
202
+
203
+ if (isEmit) {
204
+ if (value) {
205
+ return `@change="${value}"`;
206
+ }
207
+ }
208
+
209
+ if (isConditionMet && !isClick && !isCustom && !isEmpty && !isExcluded && !isSlot) {
210
+ return `${isDynamic ? ':' : ''}${formatKebabCase(key)}="${value}"`;
211
+ }
212
+ });
213
+
214
+ classNames = classNames.filter((className) => !!className);
215
+
216
+ if (classNames.length > 0) attributes.push(`class="${classNames.join(' ')}"`);
217
+
218
+ attributes = attributes.filter((attribute) => !!attribute).sort();
219
+
220
+ if (attributes) attributes.unshift('');
221
+
222
+ return args.default
223
+ ? `<${tag}${attributes.join(' ')}>${lineBreak}${tab}${args.default}${lineBreak}</${tag}>`
224
+ : `<${tag}${attributes.join(' ')} />`;
225
+ };
226
+
227
+ export const formatSnippetMinimal = (code: string) => {
228
+ return code.replace(/<[/]*template>/g, '');
229
+ };
230
+
231
+ export const getConstantByValue = (value: string) => {
232
+ const compareRecursively = (basis: string, shape: string | object, depth: number = 0): string | void => {
233
+ let output;
234
+
235
+ Object.entries(shape).forEach((entry: string[]) => {
236
+ const key = entry[0];
237
+ const value = entry[1];
238
+ const type = typeof value;
239
+
240
+ if (type === 'string' && basis === value) {
241
+ output = key;
242
+ return;
243
+ } else if (type === 'object') {
244
+ const match = compareRecursively(basis, value, depth + 1);
245
+
246
+ if (match) {
247
+ output = `${key}.${match}`;
248
+ return;
249
+ }
250
+ }
251
+ });
252
+
253
+ return output;
254
+ };
255
+
256
+ const constant = compareRecursively(value, CSS);
257
+
258
+ return constant ? `CSS.${constant}` : undefined;
259
+ };
260
+
261
+ export const getConstantsByValues = (classNames: string[]) =>
262
+ classNames.map((className) => getConstantByValue(className));
263
+
264
+ export const getKey = (input: any) => Object.keys(input)[0];
265
+
266
+ // Invert key/value pairs bc Storybook control option format is unintuitive.
267
+ export const getLabelsFromOptions = (options: any) => {
268
+ const labels: { [key: string]: string } = {};
269
+
270
+ Object.entries(options).forEach(([key, value]) => {
271
+ labels[`${value}`] = key;
272
+ });
273
+
274
+ return labels;
275
+ };
276
+
277
+ export const parameters = {
278
+ docs: {
279
+ source: {
280
+ format: 'vue',
281
+ language: 'html',
282
+ transform: formatSnippet,
283
+ },
284
+ },
285
+ };
286
+
287
+ // Prepend a key/value pair to a constant.
288
+ export const prependKeyValue = (collection: KeyValue, keyValue: KeyValue) => ({
289
+ ...keyValue,
290
+ ...collection,
291
+ });
292
+
293
+ export const prependNoneAsUndefined = (collection: KeyValue) => prependKeyValue(collection, NoneAsUndefined);
294
+
295
+ export const prependNoneAsEmpty = (collection: KeyValue) => prependKeyValue(collection, NoneAsEmpty);