@poveste/app 0.14.0 → 0.15.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 (79) hide show
  1. package/dist/bundled/app.css +26 -26
  2. package/dist/bundled/components/app/TopBarChipItem.js +1 -1
  3. package/dist/bundled/components/base/BaseEmpty.js +2 -2
  4. package/dist/bundled/components/base/BaseOverflowMenu.vue_vue_type_script_setup_true_lang.js +14 -14
  5. package/dist/bundled/components/base/BaseSelect.vue_vue_type_script_setup_true_lang.js +158 -26
  6. package/dist/bundled/components/base/BaseSplitPane.js +1 -1
  7. package/dist/bundled/components/command/PromptSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/bundled/components/panel/ControlsComponentPropItem.vue_vue_type_script_setup_true_lang.js +20 -14
  9. package/dist/bundled/components/panel/PaneTabs.vue_vue_type_script_setup_true_lang.js +6 -6
  10. package/dist/bundled/components/panel/StatePresets.vue_vue_type_script_setup_true_lang.js +78 -49
  11. package/dist/bundled/components/panel/StorySidePanel.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/bundled/components/panel/StorySourceCode.js +1 -1
  13. package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +5 -4
  14. package/dist/bundled/components/search/SearchItemContent.vue_vue_type_script_setup_true_lang.js +2 -1
  15. package/dist/bundled/components/search/SearchPane.vue_vue_type_script_setup_true_lang.js +1 -2
  16. package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
  17. package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +8 -4
  18. package/dist/bundled/components/story/StoryVariantGridItem.js +1 -1
  19. package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js +3 -3
  20. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue_vue_type_script_setup_true_lang.js +9 -6
  21. package/dist/bundled/components/story/StoryView.vue_vue_type_script_setup_true_lang.js +4 -1
  22. package/dist/bundled/components/toolbar/ToolbarTitle.js +1 -1
  23. package/dist/bundled/components/toolbar/ToolbarTitle.vue_vue_type_script_setup_true_lang.js +1 -1
  24. package/dist/bundled/components/tree/StoryGroup.vue_vue_type_script_setup_true_lang.js +2 -2
  25. package/dist/bundled/components/tree/StoryList.vue_vue_type_script_setup_true_lang.js +3 -3
  26. package/dist/bundled/components/tree/StoryListFolder.js +1 -1
  27. package/dist/bundled/components/tree/StoryListFolder.vue_vue_type_script_setup_true_lang.js +3 -3
  28. package/dist/bundled/components/tree/StoryListItem.js +1 -1
  29. package/dist/bundled/components/tree/StoryListItem.vue_vue_type_script_setup_true_lang.js +3 -3
  30. package/dist/bundled/sandbox.js +3 -2
  31. package/dist/bundled/stores/story.js +2 -2
  32. package/dist/bundled/util/commands.js +1 -1
  33. package/dist/bundled/util/dark.js +1 -1
  34. package/dist/bundled/util/events.js +1 -1
  35. package/dist/bundled/util/grid-slots.js +1 -1
  36. package/dist/bundled/util/keyboard.js +8 -14
  37. package/dist/bundled/util/mapping.js +2 -2
  38. package/dist/bundled/util/render-tracker.js +33 -0
  39. package/dist/bundled/util/variant.js +12 -2
  40. package/dist/style.css +23 -1
  41. package/package.json +13 -17
  42. package/src/__tests__/render-tracker.spec.ts +38 -0
  43. package/src/app/App.vue +1 -1
  44. package/src/app/components/app/TopBarChipItem.vue +1 -1
  45. package/src/app/components/base/BaseEmpty.vue +1 -1
  46. package/src/app/components/base/BaseListItemLink.vue +4 -2
  47. package/src/app/components/base/BaseOverflowMenu.vue +17 -16
  48. package/src/app/components/base/BaseSelect.vue +171 -15
  49. package/src/app/components/base/BaseSplitPane.vue +2 -2
  50. package/src/app/components/command/PromptSelect.vue +1 -1
  51. package/src/app/components/panel/ControlsComponentPropItem.vue +26 -15
  52. package/src/app/components/panel/PaneTabs.vue +6 -6
  53. package/src/app/components/panel/StatePresets.vue +100 -64
  54. package/src/app/components/panel/StorySidePanel.vue +1 -1
  55. package/src/app/components/panel/StorySourceCode.vue +6 -5
  56. package/src/app/components/search/SearchItemContent.vue +2 -1
  57. package/src/app/components/search/SearchPane.vue +2 -3
  58. package/src/app/components/story/StoryResponsivePreview.vue +6 -2
  59. package/src/app/components/story/StoryVariantGridItem.vue +1 -1
  60. package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +14 -8
  61. package/src/app/components/story/StoryView.vue +3 -1
  62. package/src/app/components/toolbar/ToolbarTitle.vue +2 -2
  63. package/src/app/components/tree/StoryGroup.vue +2 -2
  64. package/src/app/components/tree/StoryList.vue +2 -2
  65. package/src/app/components/tree/StoryListFolder.vue +2 -2
  66. package/src/app/components/tree/StoryListItem.vue +1 -1
  67. package/src/app/sandbox.ts +8 -2
  68. package/src/app/stores/story.ts +2 -2
  69. package/src/app/types.ts +4 -4
  70. package/src/app/util/commands.ts +1 -1
  71. package/src/app/util/dark.ts +1 -1
  72. package/src/app/util/env.ts +0 -1
  73. package/src/app/util/events.ts +6 -5
  74. package/src/app/util/grid-slots.ts +1 -1
  75. package/src/app/util/keyboard.ts +7 -11
  76. package/src/app/util/mapping.ts +2 -2
  77. package/src/app/util/render-tracker.ts +31 -0
  78. package/src/app/util/state.ts +3 -3
  79. package/src/app/util/variant.ts +12 -2
@@ -9,9 +9,9 @@ export const useStoryStore = defineStore('story', () => {
9
9
  stories.value = value
10
10
  }
11
11
 
12
- const currentStory = computed(() => stories.value.find(s => s.id === router.currentRoute.value.params.storyId))
12
+ const currentStory = computed(() => stories.value.find(s => s.id === router.currentRoute.value.params['storyId']))
13
13
 
14
- const currentVariant = computed(() => currentStory.value?.variants.find(v => v.id === router.currentRoute.value.query.variantId))
14
+ const currentVariant = computed(() => currentStory.value?.variants.find(v => v.id === router.currentRoute.value.query['variantId']))
15
15
 
16
16
  const maps = computed(() => {
17
17
  const storyMap = new Map<string, Story>()
package/src/app/types.ts CHANGED
@@ -33,10 +33,10 @@ export interface SearchResultBase {
33
33
  rank: number
34
34
  id: string
35
35
  title: string
36
- path?: string[]
37
- icon?: string
38
- iconColor?: string
39
- type?: SearchResultType
36
+ path?: string[] | undefined
37
+ icon?: string | undefined
38
+ iconColor?: string | undefined
39
+ type?: SearchResultType | undefined
40
40
  }
41
41
 
42
42
  export type SearchResult = SearchResultBase & ({
@@ -41,7 +41,7 @@ export const builtinCommands: ClientCommand[] = [
41
41
  label: 'Open Poveste Documentation',
42
42
  icon: 'carbon:help',
43
43
  clientAction: () => {
44
- window.open('https://poveste.dev/guide/getting-started.html', '_blank')
44
+ window.open('https://poveste.dev/guide/getting-started', '_blank')
45
45
  },
46
46
  },
47
47
  ]
@@ -4,7 +4,7 @@ import { povesteConfig } from './config.js'
4
4
 
5
5
  export const isDark = useDark({
6
6
  valueDark: 'ptw-dark',
7
- initialValue: povesteConfig.theme.defaultColorScheme,
7
+ ...povesteConfig.theme.defaultColorScheme ? { initialValue: povesteConfig.theme.defaultColorScheme } : {},
8
8
  storageKey: 'poveste-color-scheme',
9
9
  storage: povesteConfig.theme.storeColorScheme ? localStorage : sessionStorage,
10
10
  })
@@ -2,5 +2,4 @@
2
2
  // `navigator.userAgentData` is Chromium-only, so reading it here would simply
3
3
  // stop detecting macOS in Safari and Firefox — the two places where getting the
4
4
  // ⌘ shortcuts right matters most.
5
- // eslint-disable-next-line ts/no-deprecated
6
5
  export const isMac = navigator.platform.toLowerCase().includes('mac')
@@ -1,7 +1,7 @@
1
1
  import { EVENT_SEND } from './const'
2
2
  import { occupant } from './occupant'
3
3
 
4
- export async function logEvent(name: string, argument) {
4
+ export async function logEvent(name: string, argument: unknown) {
5
5
  const event = {
6
6
  name,
7
7
  argument: JSON.parse(stringifyEvent(argument)), // Needed for HTMLEvent that can't be cloned
@@ -20,10 +20,11 @@ export async function logEvent(name: string, argument) {
20
20
  }
21
21
  }
22
22
 
23
- function stringifyEvent(e) {
24
- const obj = {}
25
- for (const k in e) {
26
- obj[k] = e[k]
23
+ function stringifyEvent(e: unknown) {
24
+ const obj: Record<string, unknown> = {}
25
+ // `for...in` rather than `Object.entries`: an event's fields are inherited.
26
+ for (const k in e as object) {
27
+ obj[k] = Reflect.get(e as object, k)
27
28
  }
28
29
  return JSON.stringify(obj, (k, v) => {
29
30
  if (v instanceof Node) return 'Node'
@@ -67,6 +67,6 @@ export function trimSlots(slots: Slot[]): Slot[] {
67
67
  }
68
68
 
69
69
  let end = next.length
70
- while (end > 0 && !next[end - 1].visible) end--
70
+ while (end > 0 && !next[end - 1]?.visible) end--
71
71
  return end === next.length ? next : next.slice(0, end)
72
72
  }
@@ -11,7 +11,7 @@ export interface KeyboardShortcutOptions {
11
11
  event?: 'keyup' | 'keydown' | 'keypress'
12
12
  }
13
13
 
14
- const modifiers: { [i: string]: { key: string, pressed: boolean } } = {
14
+ const modifiers = {
15
15
  ctrl: { key: 'Control', pressed: false },
16
16
  alt: { key: 'Alt', pressed: false },
17
17
  shift: { key: 'Shift', pressed: false },
@@ -24,8 +24,7 @@ const trackedWindows = shallowRef<Window[]>([])
24
24
 
25
25
  function bindTracking(target: Window) {
26
26
  const onKeydown = (event: KeyboardEvent) => {
27
- for (const i in modifiers) {
28
- const mod = modifiers[i]
27
+ for (const mod of Object.values(modifiers)) {
29
28
  if (mod.key === event.key) {
30
29
  mod.pressed = true
31
30
  return
@@ -36,8 +35,7 @@ function bindTracking(target: Window) {
36
35
  const onKeyup = (event: KeyboardEvent) => {
37
36
  requestAnimationFrame(() => {
38
37
  pressedKeys.clear()
39
- for (const i in modifiers) {
40
- const mod = modifiers[i]
38
+ for (const mod of Object.values(modifiers)) {
41
39
  if (mod.key === event.key) {
42
40
  mod.pressed = false
43
41
  break
@@ -47,8 +45,8 @@ function bindTracking(target: Window) {
47
45
  }
48
46
  const onBlur = () => {
49
47
  pressedKeys.clear()
50
- for (const i in modifiers) {
51
- modifiers[i].pressed = false
48
+ for (const mod of Object.values(modifiers)) {
49
+ mod.pressed = false
52
50
  }
53
51
  }
54
52
  target.addEventListener('keydown', onKeydown)
@@ -108,10 +106,8 @@ function isMatchingCombination(combination: string): boolean {
108
106
  // `split` always yields at least one element, so this is unreachable for any
109
107
  // real combination — an empty or blank one matches nothing, which is right.
110
108
  if (!targetKey) return false
111
- for (const mod in modifiers) {
112
- const containsMod = splitted.includes(mod)
113
- const isPressed = modifiers[mod].pressed
114
- if (containsMod !== isPressed) {
109
+ for (const [name, mod] of Object.entries(modifiers)) {
110
+ if (splitted.includes(name) !== mod.pressed) {
115
111
  return false
116
112
  }
117
113
  }
@@ -28,7 +28,7 @@ export function mapFile(file: StoryFile, existingFile?: StoryFile): StoryFile {
28
28
  }
29
29
  }
30
30
  else if (key !== 'component') {
31
- result[key] = file[key]
31
+ Reflect.set(result, key, Reflect.get(file, key))
32
32
  }
33
33
  }
34
34
  }
@@ -58,7 +58,7 @@ export function mapVariant(variant: Variant, existingVariant?: Variant): Variant
58
58
  result = existingVariant
59
59
  for (const key in variant) {
60
60
  if (!copiedFromExistingVariant.includes(key)) {
61
- result[key] = variant[key]
61
+ Reflect.set(result, key, Reflect.get(variant, key))
62
62
  }
63
63
  }
64
64
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Whether the render now under way inside a realm reported a throw.
3
+ *
4
+ * The host cannot see inside the realm, so "did this render succeed" has to be
5
+ * read off the two named messages it does see. A throw reaches
6
+ * `app.config.errorHandler` during mount and `SANDBOX_READY` is emitted after
7
+ * `await host.mount()` returns, so the order is always error-then-ready — which
8
+ * makes a ready with nothing recorded since the render began a clean render.
9
+ *
10
+ * Clearing on the story and variant ids changing instead cleared the pair being
11
+ * navigated *to*, so arriving at a broken story wiped its marker, and the fixed
12
+ * story the comment was about was never reached at all: a file edited in place
13
+ * keeps its ids, so that watcher did not fire on the one path it named (#597).
14
+ */
15
+ export function createRenderTracker() {
16
+ let threw = false
17
+
18
+ return {
19
+ /** A new render is starting: what the previous one reported no longer holds. */
20
+ begin(): void {
21
+ threw = false
22
+ },
23
+ threw(): void {
24
+ threw = true
25
+ },
26
+ /** True when the render that has just reported ready said nothing before it. */
27
+ wasClean(): boolean {
28
+ return !threw
29
+ },
30
+ }
31
+ }
@@ -1,9 +1,9 @@
1
1
  import { clone, omit } from '@poveste/shared'
2
2
  import { isRef, unref } from 'vue'
3
3
 
4
- const isObject = val => val !== null && typeof val === 'object'
4
+ const isObject = (val: unknown): val is object => val !== null && typeof val === 'object'
5
5
 
6
- export function toRawDeep(val, clean = false, seen = new WeakMap()) {
6
+ export function toRawDeep(val: unknown, clean = false, seen = new WeakMap()): any {
7
7
  const unwrappedValue = isRef(val) ? unref(val) : val
8
8
 
9
9
  if (typeof unwrappedValue === 'symbol') {
@@ -31,7 +31,7 @@ export function toRawDeep(val, clean = false, seen = new WeakMap()) {
31
31
  else {
32
32
  const result = {}
33
33
  seen.set(unwrappedValue, result)
34
- toRawObject(unwrappedValue, result, clean, seen)
34
+ toRawObject(unwrappedValue as Record<any, any>, result, clean, seen)
35
35
  return result
36
36
  }
37
37
  }
@@ -10,17 +10,27 @@ import { useRoute } from 'vue-router'
10
10
  * has to tell "a variant is on its way" from "this story is waiting for the
11
11
  * reader to pick one" needs the same answer it will give — hence one predicate
12
12
  * rather than two copies of the condition (#328).
13
+ *
14
+ * Any story with variants, deliberately. It used to require a remembered choice
15
+ * or exactly one variant, which made `StoryView`'s `variants[0]` fallback
16
+ * unreachable: a story with several variants and no history satisfied neither
17
+ * clause, so the first visit of a session showed an empty panel and every visit
18
+ * after it worked, because the first one recorded the history (#724).
19
+ *
20
+ * No layout clause. Grid stories already auto-selected on revisit through the
21
+ * remembered choice, so excluding them here would auto-open them on the second
22
+ * visit and never the first — this defect, made permanent for one layout.
13
23
  */
14
24
  // A type predicate rather than `boolean`: the body already establishes that the
15
25
  // story is there, and returning `boolean` threw that away at every call site —
16
26
  // `StoryView` reads the story twice immediately after this returns true.
17
27
  export function autoSelectsVariant(story: Story | null | undefined): story is Story {
18
- return !!story && (!!story.lastSelectedVariant || story.variants.length === 1)
28
+ return !!story && story.variants.length > 0
19
29
  }
20
30
 
21
31
  export function useCurrentVariantRoute(variant: Ref<Variant>) {
22
32
  const route = useRoute()
23
- const isActive = computed(() => route.query.variantId === variant.value.id)
33
+ const isActive = computed(() => route.query['variantId'] === variant.value.id)
24
34
  const targetRoute = computed(() => ({
25
35
  ...route,
26
36
  query: {