@ohos-ports/histoire-app 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app/assets/histoire-text-dark.svg +89 -0
  3. package/dist/app/assets/histoire-text.svg +89 -0
  4. package/dist/app/assets/histoire.svg +51 -0
  5. package/dist/app/style/floating.pcss +34 -0
  6. package/dist/app/style/main.pcss +100 -0
  7. package/dist/app/style/sandbox.css +24 -0
  8. package/dist/app/style/transitions.pcss +51 -0
  9. package/dist/bundle-index.js +3 -0
  10. package/dist/bundle-main-dev.js +4 -0
  11. package/dist/bundle-main.js +5 -0
  12. package/dist/bundle-sandbox-dev.js +2 -0
  13. package/dist/bundle-sandbox.js +2 -0
  14. package/dist/bundled/App.vue.js +5 -0
  15. package/dist/bundled/App.vue2.js +167 -0
  16. package/dist/bundled/_virtual/_node-dom-env.js +188 -0
  17. package/dist/bundled/_virtual/_node-dom-polyfill.js +152 -0
  18. package/dist/bundled/_virtual/_plugin-vue_export-helper.js +10 -0
  19. package/dist/bundled/_virtual/histoire-commands.js +8 -0
  20. package/dist/bundled/_virtual/histoire-config.js +42 -0
  21. package/dist/bundled/_virtual/histoire-markdown-files.js +8 -0
  22. package/dist/bundled/_virtual/histoire-search-docs-data.js +11 -0
  23. package/dist/bundled/_virtual/histoire-search-title-data.js +11 -0
  24. package/dist/bundled/_virtual/histoire-stories.js +17 -0
  25. package/dist/bundled/_virtual/histoire-support-plugins-client.js +8 -0
  26. package/dist/bundled/_virtual/histoire-theme.js +8 -0
  27. package/dist/bundled/api.js +12 -0
  28. package/dist/bundled/app.css +116 -0
  29. package/dist/bundled/assets/histoire-text-dark.svg.js +4 -0
  30. package/dist/bundled/assets/histoire-text.svg.js +4 -0
  31. package/dist/bundled/assets/histoire.svg.js +4 -0
  32. package/dist/bundled/components/HomeView.vue.js +5 -0
  33. package/dist/bundled/components/HomeView.vue2.js +66 -0
  34. package/dist/bundled/components/app/AppHeader.vue.js +5 -0
  35. package/dist/bundled/components/app/AppHeader.vue2.js +71 -0
  36. package/dist/bundled/components/app/AppLogo.vue.js +5 -0
  37. package/dist/bundled/components/app/AppLogo.vue2.js +29 -0
  38. package/dist/bundled/components/app/Breadcrumb.vue.js +8 -0
  39. package/dist/bundled/components/app/Breadcrumb.vue2.js +91 -0
  40. package/dist/bundled/components/app/HomeCounter.vue.js +5 -0
  41. package/dist/bundled/components/app/HomeCounter.vue2.js +42 -0
  42. package/dist/bundled/components/app/InitialLoading.vue.js +5 -0
  43. package/dist/bundled/components/app/InitialLoading.vue2.js +51 -0
  44. package/dist/bundled/components/app/MobileOverlay.vue.js +5 -0
  45. package/dist/bundled/components/app/MobileOverlay.vue2.js +45 -0
  46. package/dist/bundled/components/base/BaseButton.vue.js +5 -0
  47. package/dist/bundled/components/base/BaseButton.vue2.js +39 -0
  48. package/dist/bundled/components/base/BaseCheckbox.vue.js +5 -0
  49. package/dist/bundled/components/base/BaseCheckbox.vue2.js +78 -0
  50. package/dist/bundled/components/base/BaseEmpty.vue.js +14 -0
  51. package/dist/bundled/components/base/BaseIcon.vue.js +8 -0
  52. package/dist/bundled/components/base/BaseIcon.vue2.js +29 -0
  53. package/dist/bundled/components/base/BaseKeyboardShortcut.vue.js +5 -0
  54. package/dist/bundled/components/base/BaseKeyboardShortcut.vue2.js +20 -0
  55. package/dist/bundled/components/base/BaseListItem.vue.js +5 -0
  56. package/dist/bundled/components/base/BaseListItem.vue2.js +33 -0
  57. package/dist/bundled/components/base/BaseListItemLink.vue.js +33 -0
  58. package/dist/bundled/components/base/BaseListItemLink.vue2.js +26 -0
  59. package/dist/bundled/components/base/BaseOverflowMenu.vue.js +5 -0
  60. package/dist/bundled/components/base/BaseOverflowMenu.vue2.js +100 -0
  61. package/dist/bundled/components/base/BaseOverflowTab.vue.js +36 -0
  62. package/dist/bundled/components/base/BaseOverflowTab.vue2.js +18 -0
  63. package/dist/bundled/components/base/BaseSelect.vue.js +5 -0
  64. package/dist/bundled/components/base/BaseSelect.vue2.js +77 -0
  65. package/dist/bundled/components/base/BaseSplitPane.vue.js +8 -0
  66. package/dist/bundled/components/base/BaseSplitPane.vue2.js +183 -0
  67. package/dist/bundled/components/base/BaseTab.vue.js +36 -0
  68. package/dist/bundled/components/base/BaseTab.vue2.js +18 -0
  69. package/dist/bundled/components/base/BaseTag.vue.js +13 -0
  70. package/dist/bundled/components/command/CommandPrompts.vue.js +5 -0
  71. package/dist/bundled/components/command/CommandPrompts.vue2.js +91 -0
  72. package/dist/bundled/components/command/CommandPromptsModal.vue.js +5 -0
  73. package/dist/bundled/components/command/CommandPromptsModal.vue2.js +45 -0
  74. package/dist/bundled/components/command/PromptSelect.vue.js +5 -0
  75. package/dist/bundled/components/command/PromptSelect.vue2.js +142 -0
  76. package/dist/bundled/components/command/PromptText.vue.js +5 -0
  77. package/dist/bundled/components/command/PromptText.vue2.js +67 -0
  78. package/dist/bundled/components/misc/CheckerboardPattern.vue.js +40 -0
  79. package/dist/bundled/components/misc/HatchedPattern.vue.js +12 -0
  80. package/dist/bundled/components/panel/ControlsComponentPropItem.vue.js +5 -0
  81. package/dist/bundled/components/panel/ControlsComponentPropItem.vue2.js +72 -0
  82. package/dist/bundled/components/panel/ControlsComponentProps.vue.js +5 -0
  83. package/dist/bundled/components/panel/ControlsComponentProps.vue2.js +45 -0
  84. package/dist/bundled/components/panel/ControlsComponentState.vue.js +5 -0
  85. package/dist/bundled/components/panel/ControlsComponentState.vue2.js +41 -0
  86. package/dist/bundled/components/panel/ControlsComponentStateItem.vue.js +5 -0
  87. package/dist/bundled/components/panel/ControlsComponentStateItem.vue2.js +46 -0
  88. package/dist/bundled/components/panel/PaneTabs.vue.js +5 -0
  89. package/dist/bundled/components/panel/PaneTabs.vue2.js +114 -0
  90. package/dist/bundled/components/panel/StatePresets.vue.js +5 -0
  91. package/dist/bundled/components/panel/StatePresets.vue2.js +193 -0
  92. package/dist/bundled/components/panel/StoryControls.vue.js +5 -0
  93. package/dist/bundled/components/panel/StoryControls.vue2.js +87 -0
  94. package/dist/bundled/components/panel/StoryDocs.vue.js +7 -0
  95. package/dist/bundled/components/panel/StoryDocs.vue2.js +161 -0
  96. package/dist/bundled/components/panel/StoryEvent.vue.js +5 -0
  97. package/dist/bundled/components/panel/StoryEvent.vue2.js +59 -0
  98. package/dist/bundled/components/panel/StoryEvents.vue.js +5 -0
  99. package/dist/bundled/components/panel/StoryEvents.vue2.js +53 -0
  100. package/dist/bundled/components/panel/StorySidePanel.vue.js +5 -0
  101. package/dist/bundled/components/panel/StorySidePanel.vue2.js +83 -0
  102. package/dist/bundled/components/panel/StorySourceCode.vue.js +8 -0
  103. package/dist/bundled/components/panel/StorySourceCode.vue2.js +204 -0
  104. package/dist/bundled/components/search/SearchItem.vue.js +8 -0
  105. package/dist/bundled/components/search/SearchItem.vue2.js +93 -0
  106. package/dist/bundled/components/search/SearchItemContent.vue.js +5 -0
  107. package/dist/bundled/components/search/SearchItemContent.vue2.js +71 -0
  108. package/dist/bundled/components/search/SearchLoading.vue.js +5 -0
  109. package/dist/bundled/components/search/SearchLoading.vue2.js +21 -0
  110. package/dist/bundled/components/search/SearchModal.vue.js +5 -0
  111. package/dist/bundled/components/search/SearchModal.vue2.js +51 -0
  112. package/dist/bundled/components/search/SearchPane.vue.js +5 -0
  113. package/dist/bundled/components/search/SearchPane.vue2.js +272 -0
  114. package/dist/bundled/components/search/search-docs-data.js +11 -0
  115. package/dist/bundled/components/search/search-title-data.js +11 -0
  116. package/dist/bundled/components/story/GenericMountStory.vue.js +5 -0
  117. package/dist/bundled/components/story/GenericMountStory.vue2.js +34 -0
  118. package/dist/bundled/components/story/GenericRenderStory.vue.js +5 -0
  119. package/dist/bundled/components/story/GenericRenderStory.vue2.js +39 -0
  120. package/dist/bundled/components/story/StoryResponsivePreview.vue.js +8 -0
  121. package/dist/bundled/components/story/StoryResponsivePreview.vue2.js +207 -0
  122. package/dist/bundled/components/story/StoryVariantGrid.vue.js +5 -0
  123. package/dist/bundled/components/story/StoryVariantGrid.vue2.js +146 -0
  124. package/dist/bundled/components/story/StoryVariantGridItem.vue.js +8 -0
  125. package/dist/bundled/components/story/StoryVariantGridItem.vue2.js +153 -0
  126. package/dist/bundled/components/story/StoryVariantListItem.vue.js +8 -0
  127. package/dist/bundled/components/story/StoryVariantListItem.vue2.js +55 -0
  128. package/dist/bundled/components/story/StoryVariantSingle.vue.js +8 -0
  129. package/dist/bundled/components/story/StoryVariantSingle.vue2.js +107 -0
  130. package/dist/bundled/components/story/StoryVariantSinglePreviewNative.vue.js +5 -0
  131. package/dist/bundled/components/story/StoryVariantSinglePreviewNative.vue2.js +70 -0
  132. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue.js +5 -0
  133. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue2.js +128 -0
  134. package/dist/bundled/components/story/StoryVariantSingleView.vue.js +5 -0
  135. package/dist/bundled/components/story/StoryVariantSingleView.vue2.js +66 -0
  136. package/dist/bundled/components/story/StoryView.vue.js +5 -0
  137. package/dist/bundled/components/story/StoryView.vue2.js +104 -0
  138. package/dist/bundled/components/story/StoryViewer.vue.js +8 -0
  139. package/dist/bundled/components/story/StoryViewer.vue2.js +55 -0
  140. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue.js +5 -0
  141. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue2.js +31 -0
  142. package/dist/bundled/components/toolbar/ToolbarBackground.vue.js +8 -0
  143. package/dist/bundled/components/toolbar/ToolbarBackground.vue2.js +98 -0
  144. package/dist/bundled/components/toolbar/ToolbarNewTab.vue.js +5 -0
  145. package/dist/bundled/components/toolbar/ToolbarNewTab.vue2.js +36 -0
  146. package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue.js +5 -0
  147. package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue2.js +127 -0
  148. package/dist/bundled/components/toolbar/ToolbarTextDirection.vue.js +5 -0
  149. package/dist/bundled/components/toolbar/ToolbarTextDirection.vue2.js +27 -0
  150. package/dist/bundled/components/toolbar/ToolbarTitle.vue.js +5 -0
  151. package/dist/bundled/components/toolbar/ToolbarTitle.vue2.js +26 -0
  152. package/dist/bundled/components/tree/StoryGroup.vue.js +5 -0
  153. package/dist/bundled/components/tree/StoryGroup.vue2.js +74 -0
  154. package/dist/bundled/components/tree/StoryList.vue.js +5 -0
  155. package/dist/bundled/components/tree/StoryList.vue2.js +41 -0
  156. package/dist/bundled/components/tree/StoryListFolder.vue.js +8 -0
  157. package/dist/bundled/components/tree/StoryListFolder.vue2.js +86 -0
  158. package/dist/bundled/components/tree/StoryListItem.vue.js +8 -0
  159. package/dist/bundled/components/tree/StoryListItem.vue2.js +69 -0
  160. package/dist/bundled/index.js +36 -0
  161. package/dist/bundled/plugin.js +49 -0
  162. package/dist/bundled/router.js +32 -0
  163. package/dist/bundled/sandbox.js +87 -0
  164. package/dist/bundled/stores/command.js +25 -0
  165. package/dist/bundled/stores/events.js +29 -0
  166. package/dist/bundled/stores/folder.js +54 -0
  167. package/dist/bundled/stores/preview-settings.js +19 -0
  168. package/dist/bundled/stores/story.js +43 -0
  169. package/dist/bundled/util/commands.js +57 -0
  170. package/dist/bundled/util/config.js +8 -0
  171. package/dist/bundled/util/const.js +10 -0
  172. package/dist/bundled/util/dark.js +28 -0
  173. package/dist/bundled/util/docs.js +26 -0
  174. package/dist/bundled/util/env.js +4 -0
  175. package/dist/bundled/util/events.js +33 -0
  176. package/dist/bundled/util/keyboard.js +90 -0
  177. package/dist/bundled/util/mapping.js +70 -0
  178. package/dist/bundled/util/open-in-editor.js +7 -0
  179. package/dist/bundled/util/preview-settings.js +21 -0
  180. package/dist/bundled/util/responsive.js +6 -0
  181. package/dist/bundled/util/sandbox.js +11 -0
  182. package/dist/bundled/util/scroll.js +31 -0
  183. package/dist/bundled/util/select.js +28 -0
  184. package/dist/bundled/util/state.js +41 -0
  185. package/dist/bundled/util/tooltip.js +15 -0
  186. package/dist/bundled/util/variant.js +21 -0
  187. package/dist/style.css +2853 -0
  188. package/package.json +62 -0
  189. package/postcss-scope-wrapper.cjs +35 -0
  190. package/postcss.config.cjs +9 -0
  191. package/scripts/copy.mjs +12 -0
  192. package/scripts/watchAndCopy.mjs +15 -0
  193. package/src/app/App.vue +172 -0
  194. package/src/app/api.ts +9 -0
  195. package/src/app/assets/histoire-text-dark.svg +89 -0
  196. package/src/app/assets/histoire-text.svg +89 -0
  197. package/src/app/assets/histoire.svg +51 -0
  198. package/src/app/components/HomeView.vue +61 -0
  199. package/src/app/components/app/AppHeader.vue +65 -0
  200. package/src/app/components/app/AppLogo.vue +25 -0
  201. package/src/app/components/app/Breadcrumb.vue +98 -0
  202. package/src/app/components/app/HomeCounter.vue +39 -0
  203. package/src/app/components/app/InitialLoading.vue +44 -0
  204. package/src/app/components/app/MobileOverlay.vue +33 -0
  205. package/src/app/components/base/BaseButton.vue +33 -0
  206. package/src/app/components/base/BaseCheckbox.vue +76 -0
  207. package/src/app/components/base/BaseCopyIcon.vue +34 -0
  208. package/src/app/components/base/BaseEmpty.vue +21 -0
  209. package/src/app/components/base/BaseIcon.vue +31 -0
  210. package/src/app/components/base/BaseKeyboardShortcut.vue +16 -0
  211. package/src/app/components/base/BaseListItem.vue +30 -0
  212. package/src/app/components/base/BaseListItemLink.vue +56 -0
  213. package/src/app/components/base/BaseOverflowMenu.vue +119 -0
  214. package/src/app/components/base/BaseOverflowTab.vue +47 -0
  215. package/src/app/components/base/BaseSelect.vue +75 -0
  216. package/src/app/components/base/BaseSplitPane.vue +244 -0
  217. package/src/app/components/base/BaseTab.vue +47 -0
  218. package/src/app/components/base/BaseTag.vue +5 -0
  219. package/src/app/components/command/CommandPrompts.vue +95 -0
  220. package/src/app/components/command/CommandPromptsModal.vue +41 -0
  221. package/src/app/components/command/PromptSelect.vue +142 -0
  222. package/src/app/components/command/PromptText.vue +65 -0
  223. package/src/app/components/misc/CheckerboardPattern.vue +32 -0
  224. package/src/app/components/misc/HatchedPattern.vue +13 -0
  225. package/src/app/components/panel/ControlsComponentPropItem.vue +73 -0
  226. package/src/app/components/panel/ControlsComponentProps.vue +34 -0
  227. package/src/app/components/panel/ControlsComponentState.vue +38 -0
  228. package/src/app/components/panel/ControlsComponentStateItem.vue +44 -0
  229. package/src/app/components/panel/PaneTabs.vue +84 -0
  230. package/src/app/components/panel/StatePresets.vue +199 -0
  231. package/src/app/components/panel/StoryControls.vue +97 -0
  232. package/src/app/components/panel/StoryDocs.vue +202 -0
  233. package/src/app/components/panel/StoryEvent.vue +54 -0
  234. package/src/app/components/panel/StoryEvents.vue +48 -0
  235. package/src/app/components/panel/StorySidePanel.vue +76 -0
  236. package/src/app/components/panel/StorySourceCode.vue +248 -0
  237. package/src/app/components/search/SearchItem.vue +89 -0
  238. package/src/app/components/search/SearchItemContent.vue +67 -0
  239. package/src/app/components/search/SearchLoading.vue +16 -0
  240. package/src/app/components/search/SearchModal.vue +44 -0
  241. package/src/app/components/search/SearchPane.vue +319 -0
  242. package/src/app/components/search/search-docs-data.ts +9 -0
  243. package/src/app/components/search/search-title-data.ts +9 -0
  244. package/src/app/components/search/types.ts +4 -0
  245. package/src/app/components/story/GenericMountStory.vue +35 -0
  246. package/src/app/components/story/GenericRenderStory.vue +41 -0
  247. package/src/app/components/story/StoryResponsivePreview.vue +216 -0
  248. package/src/app/components/story/StoryVariantGrid.vue +169 -0
  249. package/src/app/components/story/StoryVariantGridItem.vue +163 -0
  250. package/src/app/components/story/StoryVariantListItem.vue +52 -0
  251. package/src/app/components/story/StoryVariantSingle.vue +105 -0
  252. package/src/app/components/story/StoryVariantSinglePreviewNative.vue +66 -0
  253. package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +143 -0
  254. package/src/app/components/story/StoryVariantSingleView.vue +61 -0
  255. package/src/app/components/story/StoryView.vue +110 -0
  256. package/src/app/components/story/StoryViewer.vue +52 -0
  257. package/src/app/components/toolbar/DevOnlyToolbarOpenInEditor.vue +23 -0
  258. package/src/app/components/toolbar/ToolbarBackground.vue +81 -0
  259. package/src/app/components/toolbar/ToolbarNewTab.vue +29 -0
  260. package/src/app/components/toolbar/ToolbarResponsiveSize.vue +82 -0
  261. package/src/app/components/toolbar/ToolbarTextDirection.vue +19 -0
  262. package/src/app/components/toolbar/ToolbarTitle.vue +21 -0
  263. package/src/app/components/tree/StoryGroup.vue +73 -0
  264. package/src/app/components/tree/StoryList.vue +35 -0
  265. package/src/app/components/tree/StoryListFolder.vue +88 -0
  266. package/src/app/components/tree/StoryListItem.vue +72 -0
  267. package/src/app/index.ts +33 -0
  268. package/src/app/plugin.ts +59 -0
  269. package/src/app/router.ts +29 -0
  270. package/src/app/sandbox.ts +101 -0
  271. package/src/app/stores/command.ts +26 -0
  272. package/src/app/stores/events.ts +36 -0
  273. package/src/app/stores/folder.ts +63 -0
  274. package/src/app/stores/preview-settings.ts +18 -0
  275. package/src/app/stores/story.ts +47 -0
  276. package/src/app/style/floating.pcss +34 -0
  277. package/src/app/style/main.pcss +100 -0
  278. package/src/app/style/sandbox.css +24 -0
  279. package/src/app/style/transitions.pcss +51 -0
  280. package/src/app/types.ts +72 -0
  281. package/src/app/util/commands.ts +57 -0
  282. package/src/app/util/config.ts +5 -0
  283. package/src/app/util/const.ts +4 -0
  284. package/src/app/util/dark.ts +27 -0
  285. package/src/app/util/docs.ts +27 -0
  286. package/src/app/util/env.ts +1 -0
  287. package/src/app/util/events.ts +31 -0
  288. package/src/app/util/keyboard.ts +103 -0
  289. package/src/app/util/mapping.ts +80 -0
  290. package/src/app/util/open-in-editor.ts +3 -0
  291. package/src/app/util/preview-settings.ts +23 -0
  292. package/src/app/util/responsive.ts +3 -0
  293. package/src/app/util/sandbox.ts +9 -0
  294. package/src/app/util/scroll.ts +32 -0
  295. package/src/app/util/select.ts +30 -0
  296. package/src/app/util/state.ts +45 -0
  297. package/src/app/util/tooltip.ts +13 -0
  298. package/src/app/util/variant.ts +21 -0
  299. package/src/bundle-index.js +1 -0
  300. package/src/bundle-main-dev.js +4 -0
  301. package/src/bundle-main.js +5 -0
  302. package/src/bundle-sandbox-dev.js +2 -0
  303. package/src/bundle-sandbox.js +2 -0
  304. package/src/index.ts +1 -0
  305. package/src/shim.d.ts +10 -0
  306. package/src/virtual.d.ts +7 -0
  307. package/tailwind.config.cjs +137 -0
  308. package/tsconfig.json +53 -0
  309. package/vite.config.ts +88 -0
@@ -0,0 +1,199 @@
1
+ <script lang="ts" setup>
2
+ import type { Story, Variant } from '../../types'
3
+ import { applyState, clone, omit } from '@histoire/shared'
4
+ import { Icon } from '@iconify/vue'
5
+ import { onClickOutside, useStorage, useTimeoutFn } from '@vueuse/core'
6
+ import { computed, nextTick, onMounted, ref } from 'vue'
7
+ import { toRawDeep } from '../../util/state'
8
+ import BaseSelect from '../base/BaseSelect.vue'
9
+
10
+ const DEFAULT_ID = 'default'
11
+
12
+ const props = defineProps<{
13
+ story: Story
14
+ variant: Variant
15
+ }>()
16
+
17
+ const saveId = computed(() => `${props.story.id}:${props.variant.id}`)
18
+
19
+ const omitKeys = ['_hPropDefs']
20
+
21
+ const defaultState = clone(omit(toRawDeep(props.variant.state), omitKeys))
22
+
23
+ const selectedOption = useStorage<string>(
24
+ `_histoire-presets/${saveId.value}/selected`,
25
+ DEFAULT_ID,
26
+ )
27
+
28
+ const presetStates = useStorage<Map<string, { state: Record<string, unknown>, label: string }>>(
29
+ `_histoire-presets/${saveId.value}/states`,
30
+ new Map(),
31
+ )
32
+
33
+ const presetsOptions = computed(() => {
34
+ const options = { [DEFAULT_ID]: 'Initial state' }
35
+ presetStates.value.forEach((value, key) => {
36
+ options[key] = value.label
37
+ })
38
+ return options
39
+ })
40
+
41
+ function resetState() {
42
+ selectedOption.value = DEFAULT_ID
43
+ applyState(props.variant.state, clone(defaultState))
44
+ }
45
+
46
+ function applyPreset(id) {
47
+ if (id === DEFAULT_ID) {
48
+ resetState()
49
+ }
50
+ else if (presetStates.value.has(id)) {
51
+ applyState(props.variant.state, clone(toRawDeep(presetStates.value.get(id).state)))
52
+ }
53
+ }
54
+
55
+ onMounted(() => {
56
+ if (selectedOption.value !== DEFAULT_ID) {
57
+ applyPreset(selectedOption.value)
58
+ }
59
+ })
60
+
61
+ const input = ref<HTMLInputElement>()
62
+ const select = ref<HTMLInputElement>()
63
+ const canEdit = computed(() => selectedOption.value !== DEFAULT_ID)
64
+ const isEditing = ref(false)
65
+
66
+ async function createPreset() {
67
+ const id = (new Date()).getTime().toString()
68
+
69
+ presetStates.value.set(id, { state: clone(omit(toRawDeep(props.variant.state), omitKeys)), label: 'New preset' })
70
+ selectedOption.value = id
71
+ isEditing.value = true
72
+ await nextTick()
73
+ input.value.select()
74
+ }
75
+
76
+ const savedNotif = ref(false)
77
+ const savedTimeout = useTimeoutFn(() => {
78
+ savedNotif.value = false
79
+ }, 1000)
80
+
81
+ async function savePreset() {
82
+ if (!canEdit.value) return
83
+
84
+ const preset = presetStates.value.get(selectedOption.value)
85
+ preset.state = clone(omit(toRawDeep(props.variant.state), omitKeys))
86
+ savedNotif.value = true
87
+ savedTimeout.start()
88
+ }
89
+
90
+ function deletePreset(id) {
91
+ // @TODO custom confirm modal UI
92
+ // eslint-disable-next-line no-alert
93
+ if (!confirm('Are you sure you want to delete this preset?')) {
94
+ return
95
+ }
96
+
97
+ if (selectedOption.value === id) {
98
+ resetState()
99
+ }
100
+ presetStates.value.delete(id)
101
+ }
102
+
103
+ async function startEditing() {
104
+ if (!canEdit.value) {
105
+ return
106
+ }
107
+
108
+ isEditing.value = true
109
+ await nextTick()
110
+ input.value.select()
111
+ }
112
+
113
+ function stopEditing() {
114
+ isEditing.value = false
115
+ }
116
+
117
+ onClickOutside(select, stopEditing)
118
+ </script>
119
+
120
+ <template>
121
+ <div class="histoire-state-presets htw-flex htw-gap-2 htw-w-full htw-items-center">
122
+ <div
123
+ ref="select"
124
+ class="htw-flex-1 htw-min-w-0"
125
+ >
126
+ <BaseSelect
127
+ v-model="selectedOption"
128
+ :options="presetsOptions"
129
+ @dblclick="startEditing()"
130
+ @keydown.enter="stopEditing()"
131
+ @keydown.escape="stopEditing()"
132
+ @select="id => applyPreset(id)"
133
+ >
134
+ <template #default="{ label }">
135
+ <input
136
+ v-if="isEditing"
137
+ ref="input"
138
+ v-model="presetStates.get(selectedOption).label"
139
+ type="text"
140
+ class="htw-text-inherit htw-bg-transparent htw-w-full htw-h-full htw-outline-none"
141
+ @click.stop.prevent
142
+ >
143
+
144
+ <div
145
+ v-else
146
+ class="htw-flex htw-items-center htw-gap-2"
147
+ >
148
+ <span class="htw-flex-1 htw-truncate">
149
+ {{ label }}
150
+ </span>
151
+ <Icon
152
+ v-if="canEdit"
153
+ v-tooltip="'Rename this preset'"
154
+ icon="carbon:edit"
155
+ class="htw-flex-none htw-cursor-pointer htw-w-4 htw-h-4 hover:htw-text-primary-500 htw-opacity-50 hover:htw-opacity-100 dark:hover:htw-text-primary-400 htw-text-gray-900 dark:htw-text-gray-100"
156
+ @click.stop="startEditing()"
157
+ />
158
+ </div>
159
+ </template>
160
+
161
+ <template #option="{ label, value }">
162
+ <div class="htw-flex htw-gap-2 htw-items-center">
163
+ <span
164
+ class="htw-flex-1 htw-truncate"
165
+ >{{ label }}</span>
166
+ <Icon
167
+ v-if="value !== DEFAULT_ID"
168
+ v-tooltip="'Delete this preset'"
169
+ icon="carbon:trash-can"
170
+ class="htw-flex-none htw-cursor-pointer htw-w-4 htw-h-4 hover:htw-text-primary-500 htw-opacity-50 hover:htw-opacity-100 dark:hover:htw-text-primary-400 htw-text-gray-900 dark:htw-text-gray-100"
171
+ @click.stop="deletePreset(value)"
172
+ />
173
+ </div>
174
+ </template>
175
+ </BaseSelect>
176
+ </div>
177
+ <Icon
178
+ v-tooltip="savedNotif ? 'Saved!' : canEdit ? 'Save to preset' : null"
179
+ :icon="savedNotif ? 'carbon:checkmark' : 'carbon:save'"
180
+ class="htw-cursor-pointer htw-w-4 htw-h-4 hover:htw-text-primary-500 dark:hover:htw-text-primary-400 htw-text-gray-900 dark:htw-text-gray-100"
181
+ :class="[
182
+ canEdit ? 'htw-opacity-50 hover:htw-opacity-100' : 'htw-opacity-25 htw-pointer-events-none',
183
+ ]"
184
+ @click="savePreset()"
185
+ />
186
+ <Icon
187
+ v-tooltip="'Create new preset'"
188
+ icon="carbon:add-alt"
189
+ class="htw-cursor-pointer htw-w-4 htw-h-4 hover:htw-text-primary-500 htw-opacity-50 hover:htw-opacity-100 dark:hover:htw-text-primary-400 htw-text-gray-900 dark:htw-text-gray-100"
190
+ @click="createPreset()"
191
+ />
192
+ <Icon
193
+ v-tooltip="'Reset to initial state'"
194
+ icon="carbon:reset"
195
+ class="htw-cursor-pointer htw-w-4 htw-h-4 hover:htw-text-primary-500 htw-opacity-50 hover:htw-opacity-100 dark:hover:htw-text-primary-400 htw-text-gray-900 dark:htw-text-gray-100"
196
+ @click="resetState()"
197
+ />
198
+ </div>
199
+ </template>
@@ -0,0 +1,97 @@
1
+ <script lang="ts" setup>
2
+ import type { PropType } from 'vue'
3
+ import type { Story, Variant } from '../../types'
4
+ import { Icon } from '@iconify/vue'
5
+ import { computed, ref, watch } from 'vue'
6
+ import BaseEmpty from '../base/BaseEmpty.vue'
7
+ import GenericRenderStory from '../story/GenericRenderStory.vue'
8
+ import ControlsComponentProps from './ControlsComponentProps.vue'
9
+ import ControlsComponentState from './ControlsComponentState.vue'
10
+ import StatePresets from './StatePresets.vue'
11
+
12
+ const props = defineProps({
13
+ variant: {
14
+ type: Object as PropType<Variant>,
15
+ required: true,
16
+ },
17
+
18
+ story: {
19
+ type: Object as PropType<Story>,
20
+ required: true,
21
+ },
22
+ })
23
+
24
+ // Wait for controls render before applying presets
25
+ const ready = ref(false)
26
+
27
+ watch(() => props.variant, () => {
28
+ ready.value = false
29
+ })
30
+
31
+ const hasCustomControls = computed(() => props.variant.slots().controls || props.story.slots().controls)
32
+
33
+ const hasInitState = computed(() => Object
34
+ .entries(props.variant.state || {})
35
+ .filter(([key]) => !key.startsWith('_h'))
36
+ .length > 0)
37
+ </script>
38
+
39
+ <template>
40
+ <div
41
+ data-test-id="story-controls"
42
+ class="histoire-story-controls htw-flex htw-flex-col htw-divide-y htw-divide-gray-100 dark:htw-divide-gray-750"
43
+ >
44
+ <!-- Toolbar -->
45
+ <div
46
+ class="htw-h-9 htw-flex-none htw-px-2 htw-flex htw-items-center"
47
+ >
48
+ <StatePresets
49
+ v-if="ready || !hasCustomControls"
50
+ :story="story"
51
+ :variant="variant"
52
+ />
53
+ </div>
54
+
55
+ <!-- Custom controls -->
56
+ <GenericRenderStory
57
+ v-if="hasCustomControls"
58
+ :key="`${story.id}-${variant.id}`"
59
+ slot-name="controls"
60
+ :variant="variant"
61
+ :story="story"
62
+ class="__histoire-render-custom-controls htw-flex-none"
63
+ @ready="ready = true"
64
+ />
65
+
66
+ <!-- Init state -->
67
+ <div
68
+ v-else-if="hasInitState"
69
+ >
70
+ <ControlsComponentState
71
+ class="htw-flex-none htw-my-2"
72
+ :variant="variant"
73
+ />
74
+ </div>
75
+
76
+ <BaseEmpty v-else-if="!variant.state?._hPropDefs?.length">
77
+ <Icon
78
+ icon="carbon:audio-console"
79
+ class="htw-w-8 htw-h-8 htw-opacity-50 htw-mb-6"
80
+ />
81
+ <span>No controls available for this story</span>
82
+ </BaseEmpty>
83
+
84
+ <!-- Auto props -->
85
+ <div
86
+ v-if="variant.state?._hPropDefs?.length"
87
+ >
88
+ <ControlsComponentProps
89
+ v-for="(def, index) of variant.state._hPropDefs"
90
+ :key="index"
91
+ :variant="variant"
92
+ :definition="def"
93
+ class="htw-flex-none htw-my-2"
94
+ />
95
+ </div>
96
+ </div>
97
+ </template>
@@ -0,0 +1,202 @@
1
+ <script lang="ts">
2
+ import type { PropType, Ref } from 'vue'
3
+ import type { Story } from '../../types'
4
+ import { Icon } from '@iconify/vue'
5
+ import { markdownFiles } from 'virtual:$histoire-markdown-files'
6
+ import { computed, nextTick, ref, toRefs, watch, watchEffect } from 'vue'
7
+ import { useRoute, useRouter } from 'vue-router'
8
+ import { histoireConfig } from '../../util/config.js'
9
+ import BaseEmpty from '../base/BaseEmpty.vue'
10
+ import DevOnlyToolbarOpenInEditor from '../toolbar/DevOnlyToolbarOpenInEditor.vue'
11
+
12
+ export function useStoryDoc(story: Ref<Story>) {
13
+ const renderedDoc = ref('')
14
+
15
+ watchEffect(async () => {
16
+ // Markdown file
17
+ const mdKey = story.value.file.filePath.replace(/\.(\w*)$/, '.md')
18
+ if (markdownFiles[mdKey]) {
19
+ const md = await markdownFiles[mdKey]()
20
+ renderedDoc.value = md.html
21
+ return
22
+ }
23
+
24
+ // Custom blocks (Vue)
25
+ // @TODO extract
26
+ let comp = story.value.file?.component
27
+ if (comp) {
28
+ if (comp.__asyncResolved) {
29
+ comp = comp.__asyncResolved
30
+ }
31
+ else if (comp.__asyncLoader) {
32
+ comp = await comp.__asyncLoader()
33
+ }
34
+ else if (typeof comp === 'function') {
35
+ try {
36
+ comp = await comp()
37
+ }
38
+ catch (e) {
39
+ // Noop
40
+ // Could be a class that requires `new com()`
41
+ }
42
+ }
43
+ if (comp?.default) {
44
+ comp = comp.default
45
+ }
46
+ renderedDoc.value = comp.doc
47
+ }
48
+ })
49
+
50
+ return {
51
+ renderedDoc,
52
+ }
53
+ }
54
+ </script>
55
+
56
+ <script lang="ts" setup>
57
+ const props = defineProps({
58
+ story: {
59
+ type: Object as PropType<Story>,
60
+ required: true,
61
+ },
62
+
63
+ standalone: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ })
68
+
69
+ const emit = defineEmits<{
70
+ (e: 'scrollTop'): void
71
+ }>()
72
+
73
+ const { story } = toRefs(props)
74
+
75
+ const { renderedDoc } = useStoryDoc(story)
76
+
77
+ // Markdown links to other stories
78
+ const router = useRouter()
79
+
80
+ // we are just using URL to parse the pathname and hash - the base doesn't
81
+ // matter and is only passed to support same-host hrefs.
82
+ const fakeHost = `http://a.com`
83
+
84
+ function onClick(e: MouseEvent) {
85
+ const link = (e.target as Element).closest('a')
86
+ if (
87
+ link
88
+ && link.getAttribute('data-route')
89
+ && !e.ctrlKey
90
+ && !e.shiftKey
91
+ && !e.altKey
92
+ && !e.metaKey
93
+ && link.target !== `_blank`
94
+ ) {
95
+ e.preventDefault()
96
+ const url = new URL(link.href, fakeHost)
97
+ const targetHref = url.pathname + url.search + url.hash
98
+ router.push(targetHref)
99
+ }
100
+ }
101
+
102
+ // Handle URL anchor
103
+
104
+ function getHash() {
105
+ const hash = location.hash
106
+ if (histoireConfig.routerMode === 'hash') {
107
+ const index = hash.indexOf('#', 1)
108
+ if (index !== -1) {
109
+ return hash.slice(index)
110
+ }
111
+ else {
112
+ return undefined
113
+ }
114
+ }
115
+ return hash
116
+ }
117
+
118
+ async function scrollToAnchor() {
119
+ await nextTick()
120
+ const hash = getHash()
121
+ if (hash) {
122
+ const anchor = document.querySelector(decodeURIComponent(hash))
123
+ if (anchor) {
124
+ anchor.scrollIntoView()
125
+ return
126
+ }
127
+ }
128
+ emit('scrollTop')
129
+ }
130
+
131
+ watch(renderedDoc, () => {
132
+ scrollToAnchor()
133
+ }, {
134
+ immediate: true,
135
+ })
136
+
137
+ // Fix anchor links with router mode 'hash'
138
+
139
+ const renderedEl = ref<HTMLElement>()
140
+ const route = useRoute()
141
+
142
+ async function patchAnchorLinks() {
143
+ await nextTick()
144
+ if (histoireConfig.routerMode === 'hash' && renderedEl.value) {
145
+ const links = renderedEl.value.querySelectorAll('a.header-anchor')
146
+ for (const link of links) {
147
+ const href = link.getAttribute('href')
148
+ if (href) {
149
+ link.setAttribute('href', `#${route.path + href}`)
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ watch(renderedDoc, () => {
156
+ patchAnchorLinks()
157
+ }, {
158
+ immediate: true,
159
+ })
160
+
161
+ // Open in editor
162
+
163
+ const filePath = computed(() => story.value.file?.docsFilePath ?? (props.standalone && story.value.file?.filePath))
164
+ </script>
165
+
166
+ <template>
167
+ <div
168
+ class="histoire-story-docs"
169
+ @click.capture="onClick"
170
+ >
171
+ <div
172
+ v-if="__HISTOIRE_DEV__ && renderedDoc && filePath"
173
+ class="htw-flex htw-items-center htw-gap-2 htw-p-2"
174
+ :class="{
175
+ 'htw-pt-4': !standalone,
176
+ }"
177
+ >
178
+ <DevOnlyToolbarOpenInEditor
179
+ v-if="filePath"
180
+ :file="filePath"
181
+ tooltip="Edit docs in editor"
182
+ />
183
+ </div>
184
+
185
+ <BaseEmpty
186
+ v-if="!renderedDoc"
187
+ >
188
+ <Icon
189
+ icon="carbon:document-unknown"
190
+ class="htw-w-8 htw-h-8 htw-opacity-50 htw-mb-6"
191
+ />
192
+ No documentation available
193
+ </BaseEmpty>
194
+ <div
195
+ v-else
196
+ ref="renderedEl"
197
+ class="htw-prose dark:htw-prose-invert htw-p-4 htw-max-w-none"
198
+ data-test-id="story-docs"
199
+ v-html="renderedDoc"
200
+ />
201
+ </div>
202
+ </template>
@@ -0,0 +1,54 @@
1
+ <script lang="ts" setup>
2
+ import type { HstEvent } from '../../stores/events'
3
+ import { computed } from 'vue'
4
+
5
+ const props = defineProps<{
6
+ event: HstEvent
7
+ }>()
8
+
9
+ const formattedArgument = computed(() => {
10
+ switch (typeof props.event.argument) {
11
+ case 'string':
12
+ return `"${props.event.argument}"`
13
+ case 'object':
14
+ return `{ ${Object.keys(props.event.argument).map(key => `${key}: ${props.event.argument[key]}`).join(', ')} }`
15
+ default:
16
+ return props.event.argument
17
+ }
18
+ })
19
+ </script>
20
+
21
+ <template>
22
+ <VDropdown
23
+ class="histoire-story-event htw-group"
24
+ placement="right"
25
+ data-test-id="event-item"
26
+ >
27
+ <template #default="{ shown }">
28
+ <div
29
+ class="group-hover:htw-bg-primary-100 dark:group-hover:htw-bg-primary-700 htw-cursor-pointer htw-py-2 htw-px-4 htw-flex htw-items-baseline htw-gap-1 htw-leading-normal"
30
+ :class="[
31
+ shown ? 'htw-bg-primary-50 dark:htw-bg-primary-600' : 'group-odd:htw-bg-gray-100/50 dark:group-odd:htw-bg-gray-750/40',
32
+ ]"
33
+ >
34
+ <span
35
+ :class="{
36
+ 'htw-text-primary-500': shown,
37
+ }"
38
+ >
39
+ {{ event.name }}
40
+ </span>
41
+ <span
42
+ v-if="event.argument"
43
+ class="htw-text-xs htw-opacity-50 htw-truncate"
44
+ >{{ formattedArgument }}</span>
45
+ </div>
46
+ </template>
47
+
48
+ <template #popper>
49
+ <div class="htw-overflow-auto htw-max-w-[400px] htw-max-h-[400px]">
50
+ <pre class="htw-p-4">{{ event.argument }}</pre>
51
+ </div>
52
+ </template>
53
+ </VDropdown>
54
+ </template>
@@ -0,0 +1,48 @@
1
+ <script lang="ts" setup>
2
+ import { Icon } from '@iconify/vue'
3
+ import { computed, nextTick, onMounted, ref, watch } from 'vue'
4
+ import { useEventsStore } from '../../stores/events'
5
+ import BaseEmpty from '../base/BaseEmpty.vue'
6
+ import StoryEvent from './StoryEvent.vue'
7
+
8
+ const eventsStore = useEventsStore()
9
+
10
+ const hasEvents = computed(() => eventsStore.events.length)
11
+
12
+ onMounted(resetUnseen)
13
+ watch(() => eventsStore.unseen, resetUnseen)
14
+
15
+ async function resetUnseen() {
16
+ if (eventsStore.unseen > 0) {
17
+ eventsStore.unseen = 0
18
+ }
19
+ await nextTick()
20
+ eventsElement.value.scrollTo({ top: eventsElement.value.scrollHeight })
21
+ }
22
+
23
+ const eventsElement = ref<HTMLDivElement>()
24
+ </script>
25
+
26
+ <template>
27
+ <div
28
+ ref="eventsElement"
29
+ class="histoire-story-events"
30
+ >
31
+ <BaseEmpty
32
+ v-if="!hasEvents"
33
+ >
34
+ <Icon
35
+ icon="carbon:event-schedule"
36
+ class="htw-w-8 htw-h-8 htw-opacity-50 htw-mb-6"
37
+ />
38
+ No event fired
39
+ </BaseEmpty>
40
+ <div v-else>
41
+ <StoryEvent
42
+ v-for="(event, key) of eventsStore.events"
43
+ :key="key"
44
+ :event="event"
45
+ />
46
+ </div>
47
+ </div>
48
+ </template>
@@ -0,0 +1,76 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+ import { useRoute } from 'vue-router'
4
+ import { useStoryStore } from '../../stores/story'
5
+
6
+ import BaseEmpty from '../base/BaseEmpty.vue'
7
+ import BaseSplitPane from '../base/BaseSplitPane.vue'
8
+ import PaneTabs from './PaneTabs.vue'
9
+ import StoryControls from './StoryControls.vue'
10
+ import StoryDocs from './StoryDocs.vue'
11
+ import StoryEvents from './StoryEvents.vue'
12
+ import StorySourceCode from './StorySourceCode.vue'
13
+
14
+ const storyStore = useStoryStore()
15
+
16
+ const route = useRoute()
17
+
18
+ const panelContentComponent = computed(() => {
19
+ switch (route.query.tab) {
20
+ case 'docs':
21
+ return StoryDocs
22
+ case 'events':
23
+ return StoryEvents
24
+ default:
25
+ return StoryControls
26
+ }
27
+ })
28
+ </script>
29
+
30
+ <template>
31
+ <BaseEmpty
32
+ v-if="!storyStore.currentVariant"
33
+ class="histoire-story-side-panel histoire-selection"
34
+ >
35
+ <span>Select a variant</span>
36
+ </BaseEmpty>
37
+
38
+ <BaseEmpty
39
+ v-else-if="!storyStore.currentVariant.configReady || !storyStore.currentVariant.previewReady"
40
+ class="histoire-story-side-panel histoire-loading"
41
+ >
42
+ <span>Loading...</span>
43
+ </BaseEmpty>
44
+
45
+ <BaseSplitPane
46
+ v-else
47
+ save-id="story-sidepane"
48
+ orientation="portrait"
49
+ class="histoire-story-side-panel histoire-loaded htw-h-full"
50
+ data-test-id="story-side-panel"
51
+ >
52
+ <template #first>
53
+ <div class="htw-flex htw-flex-col htw-h-full">
54
+ <PaneTabs
55
+ :story="storyStore.currentStory"
56
+ :variant="storyStore.currentVariant"
57
+ />
58
+
59
+ <component
60
+ :is="panelContentComponent"
61
+ :story="storyStore.currentStory"
62
+ :variant="storyStore.currentVariant"
63
+ class="htw-h-full htw-overflow-auto"
64
+ />
65
+ </div>
66
+ </template>
67
+
68
+ <template #last>
69
+ <StorySourceCode
70
+ :story="storyStore.currentStory"
71
+ :variant="storyStore.currentVariant"
72
+ class="htw-h-full"
73
+ />
74
+ </template>
75
+ </BaseSplitPane>
76
+ </template>