@globalbrain/sefirot 4.30.1 → 4.31.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.
package/config/nuxt.js CHANGED
@@ -5,9 +5,6 @@ import icons from 'unplugin-icons/nuxt'
5
5
  import { mergeConfig } from 'vite'
6
6
  import { baseConfig as baseViteConfig } from './vite.js'
7
7
 
8
- delete baseViteConfig.plugins
9
- delete baseViteConfig.resolve?.alias
10
-
11
8
  export const baseConfig = {
12
9
  alias: { sefirot: fileURLToPath(new URL('../lib', import.meta.url)) },
13
10
  app: { teleportId: 'sefirot-modals' },
@@ -23,7 +20,13 @@ export const baseConfig = {
23
20
  ],
24
21
  postcss: { plugins: { 'postcss-nested': {} } },
25
22
  telemetry: false,
26
- vite: baseViteConfig
23
+ vite: {
24
+ ...baseViteConfig,
25
+ resolve: { ...baseViteConfig.resolve, alias: {} },
26
+ plugins: baseViteConfig.plugins?.filter(
27
+ (plugin) => plugin && 'name' in plugin && plugin.name !== 'unplugin-icons'
28
+ )
29
+ }
27
30
  }
28
31
 
29
32
  export function defineConfig(config = {}) {
package/config/vite.js CHANGED
@@ -1,16 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- /**
4
- * Adapted from
5
- * @see https://github.com/unplugin/unplugin-icons/blob/67fd9b7791dc1754cb8dc46b854b22c8bb4cf380/src/core/compilers/vue3.ts
6
- * @see https://github.com/unplugin/unplugin-icons/blob/639ec9691e022e52c641d0f96f585dbf04dab095/src/core/svgId.ts
7
- *
8
- * Original licenses:
9
- *
10
- * Copyright (c) 2020 Anthony Fu <https://github.com/antfu>
11
- * @license MIT
12
- */
13
-
14
3
  import { fileURLToPath } from 'node:url'
15
4
  import MagicString from 'magic-string'
16
5
  import icons from 'unplugin-icons/vite'
@@ -48,6 +37,7 @@ export const baseConfig = {
48
37
 
49
38
  // list the client-side direct dependencies/peerDependencies which get bundled
50
39
  dedupe: [
40
+ '@popperjs/core',
51
41
  '@sentry/browser',
52
42
  '@sentry/vue',
53
43
  '@tanstack/vue-virtual',
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { type Component, ref } from 'vue'
2
+ import { type Component, ref, useTemplateRef } from 'vue'
3
3
  import { type DropdownSection, useManualDropdownPosition } from '../composables/Dropdown'
4
4
  import { useFlyout } from '../composables/Flyout'
5
5
  import SButton, { type Mode, type Size, type Tooltip, type Type } from './SButton.vue'
@@ -29,21 +29,52 @@ const props = withDefaults(defineProps<{
29
29
  dropdownAlign: 'left'
30
30
  })
31
31
 
32
- const container = ref<any>(null)
32
+ const containerRef = useTemplateRef('container')
33
+ const dropdownRef = useTemplateRef('dropdown')
33
34
 
34
- const { isOpen, toggle } = useFlyout(container)
35
- const { position, update: updatePosition } = useManualDropdownPosition(container)
35
+ const { isOpen, toggle } = useFlyout(containerRef)
36
+ const { position: verticalPlacement, update: updateVerticalPlacement }
37
+ = useManualDropdownPosition(containerRef)
38
+
39
+ const actualAlign = ref(props.dropdownAlign)
40
+
41
+ function calculateOptimalAlign(dropdownElement: HTMLElement): 'left' | 'right' {
42
+ // Temporarily show the dropdown to measure it (similar to tooltip approach)
43
+ const originalDisplay = dropdownElement.style.display
44
+ dropdownElement.style.display = 'block'
45
+ const dropdownRect = dropdownElement.getBoundingClientRect()
46
+ dropdownElement.style.display = originalDisplay
47
+
48
+ const dropdownWidth = dropdownRect.width
49
+
50
+ const viewportWidth = window.innerWidth
51
+ const containerRect = containerRef.value!.getBoundingClientRect()
52
+
53
+ const spaceOnRight = viewportWidth - containerRect.left
54
+ const spaceOnLeft = containerRect.right
55
+
56
+ if (props.dropdownAlign === 'left') {
57
+ return spaceOnRight >= dropdownWidth ? 'left' : 'right'
58
+ }
59
+
60
+ return spaceOnLeft >= dropdownWidth ? 'right' : 'left'
61
+ }
36
62
 
37
63
  async function onOpen() {
38
64
  if (!props.disabled) {
39
- updatePosition()
65
+ updateVerticalPlacement()
66
+
67
+ if (dropdownRef.value) {
68
+ actualAlign.value = calculateOptimalAlign(dropdownRef.value)
69
+ }
70
+
40
71
  toggle()
41
72
  }
42
73
  }
43
74
  </script>
44
75
 
45
76
  <template>
46
- <div class="SActionMenu" :class="[{ block }, dropdownAlign]" ref="container">
77
+ <div class="SActionMenu" :class="[{ block }, actualAlign]" ref="container">
47
78
  <div class="button">
48
79
  <SButton
49
80
  :tag
@@ -64,7 +95,12 @@ async function onOpen() {
64
95
  @click="onOpen"
65
96
  />
66
97
  </div>
67
- <div v-if="isOpen" class="dropdown" :class="position">
98
+ <div
99
+ class="dropdown"
100
+ :class="verticalPlacement"
101
+ :style="{ display: isOpen ? 'block' : 'none' }"
102
+ ref="dropdown"
103
+ >
68
104
  <SDropdown :sections="options" />
69
105
  </div>
70
106
  </div>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { useLinkifyIt } from 'sefirot/composables/Markdown'
3
2
  import { computed } from 'vue'
3
+ import { useLinkifyIt } from '../composables/Markdown'
4
4
  import { useHasSlotContent } from '../composables/Utils'
5
5
  import SDescEmpty from './SDescEmpty.vue'
6
6
 
@@ -1,6 +1,6 @@
1
- import { useHttpConfig } from 'sefirot/stores/HttpConfig'
2
1
  import { type Ref, type WatchSource, ref, watch } from 'vue'
3
2
  import { Http } from '../http/Http'
3
+ import { useHttpConfig } from '../stores/HttpConfig'
4
4
  import { tryOnMounted } from './Utils'
5
5
 
6
6
  export interface Query<Data = any> {
@@ -1,22 +1,24 @@
1
- import { type HttpOptions } from 'sefirot/stores/HttpConfig'
2
- import { useSetupHttp } from './Http'
3
- import { type HasLang, useSetupLang } from './Lang'
4
- import { type HasTheme, useSetupTheme } from './Theme'
1
+ import { type HttpOptions, useHttpConfig } from '../stores/HttpConfig'
2
+ import { type Lang, getBrowserLang, provideLang } from './Lang'
3
+ import { type Theme, useTheme } from './Theme'
5
4
 
6
- export interface SetupAppUser extends HasLang, HasTheme {}
5
+ export interface SetupAppUser {
6
+ lang?: Lang
7
+ theme?: Theme
8
+ }
7
9
 
8
10
  export interface SetupAppOptions {
9
11
  http?: HttpOptions
10
12
  }
11
13
 
12
14
  export function useSetupApp(): (user?: SetupAppUser | null, options?: SetupAppOptions) => void {
13
- const setupLang = useSetupLang()
14
- const setupTheme = useSetupTheme()
15
- const setupHttp = useSetupHttp()
15
+ const theme = useTheme()
16
+ const httpConfig = useHttpConfig()
16
17
 
17
18
  return (user, options) => {
18
- setupLang(user)
19
- setupTheme(user)
20
- setupHttp(user, options?.http)
19
+ const lang = user?.lang ?? getBrowserLang()
20
+ provideLang(lang)
21
+ if (user?.theme) { theme.value = user.theme }
22
+ httpConfig.apply({ lang, ...options?.http })
21
23
  }
22
24
  }
@@ -11,20 +11,8 @@ export interface TransMessages<T> {
11
11
  ja: T
12
12
  }
13
13
 
14
- export interface HasLang {
15
- lang: Lang
16
- }
17
-
18
14
  export const SefirotLangKey: InjectionKey<Lang> = Symbol.for('sefirot-lang-key')
19
15
 
20
- export function useSetupLang(): (user?: HasLang | null) => void {
21
- const browserLang = useBrowserLang()
22
-
23
- return (user) => {
24
- provideLang(user?.lang ?? browserLang)
25
- }
26
- }
27
-
28
16
  export function provideLang(lang: Lang) {
29
17
  getCurrentInstance()!.appContext.app._context.provides[SefirotLangKey] = lang
30
18
  }
@@ -33,12 +21,16 @@ export function useLang(): Lang {
33
21
  return inject(SefirotLangKey, 'en')
34
22
  }
35
23
 
36
- export function useBrowserLang(): Lang {
37
- const lang = navigator.language
38
-
24
+ export function getBrowserLang(): Lang {
25
+ const lang = String(globalThis.navigator?.language || 'en')
39
26
  return lang.split('-')[0] === 'ja' ? 'ja' : 'en'
40
27
  }
41
28
 
29
+ /** @deprecated use `getBrowserLang` instead */
30
+ export function useBrowserLang(): Lang {
31
+ return getBrowserLang()
32
+ }
33
+
42
34
  export function useTrans<T>(messages: TransMessages<T>): Trans<T> {
43
35
  const lang = useLang()
44
36
 
@@ -3,18 +3,6 @@ import { type WritableComputedRef, computed } from 'vue'
3
3
 
4
4
  export type Theme = 'light' | 'dark'
5
5
 
6
- export interface HasTheme {
7
- theme: Theme
8
- }
9
-
10
- export function useSetupTheme(): (user?: HasTheme | null) => void {
11
- const theme = useTheme()
12
-
13
- return (user) => {
14
- theme.value = user?.theme ?? 'light'
15
- }
16
- }
17
-
18
6
  export function useTheme(): WritableComputedRef<Theme> {
19
7
  const _isDark = useDark()
20
8
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
3
  "type": "module",
4
- "version": "4.30.1",
4
+ "version": "4.31.0",
5
5
  "packageManager": "pnpm@9.15.4",
6
6
  "description": "Vue Components for Global Brain Design System.",
7
7
  "author": "Kia Ishii <ka.ishii@globalbrains.com>",
@@ -45,10 +45,11 @@
45
45
  "peerDependencies": {
46
46
  "@iconify-json/ph": "^1.2.2",
47
47
  "@iconify-json/ri": "^1.2.5",
48
+ "@popperjs/core": "^2.11.8",
48
49
  "@types/body-scroll-lock": "^3.1.2",
49
50
  "@types/lodash-es": "^4.17.12",
50
51
  "@types/markdown-it": "^14.1.2",
51
- "@vue/reactivity": "^3.5.16",
52
+ "@vue/reactivity": "^3.5.18",
52
53
  "@vuelidate/core": "^2.0.3",
53
54
  "@vuelidate/validators": "^2.0.4",
54
55
  "@vueuse/core": "^12 || ^13",
@@ -59,15 +60,15 @@
59
60
  "markdown-it": "^14.1.0",
60
61
  "normalize.css": "^8.0.1",
61
62
  "pinia": "^3.0.3",
62
- "postcss": "^8.5.5",
63
+ "postcss": "^8.5.6",
63
64
  "postcss-nested": "^7.0.2",
64
65
  "v-calendar": "3.0.1",
65
- "vue": "^3.5.16",
66
+ "vue": "^3.5.18",
66
67
  "vue-router": "^4.5.1"
67
68
  },
68
69
  "dependencies": {
69
- "@sentry/browser": "^9.29.0",
70
- "@sentry/vue": "^9.29.0",
70
+ "@sentry/browser": "^10.5.0",
71
+ "@sentry/vue": "^10.5.0",
71
72
  "@tanstack/vue-virtual": "3.0.0-beta.62",
72
73
  "@tinyhttp/content-disposition": "^2.2.2",
73
74
  "@tinyhttp/cookie": "^2.1.1",
@@ -81,21 +82,22 @@
81
82
  "magic-string": "^0.30.17",
82
83
  "ofetch": "^1.4.1",
83
84
  "qs": "^6.14.0",
84
- "unplugin-icons": "^22.1.0"
85
+ "unplugin-icons": "^22.2.0"
85
86
  },
86
87
  "devDependencies": {
87
88
  "@globalbrain/eslint-config": "^1.7.1",
88
89
  "@histoire/plugin-vue": "0.16.5",
89
90
  "@iconify-json/ph": "^1.2.2",
90
91
  "@iconify-json/ri": "^1.2.5",
92
+ "@popperjs/core": "^2.11.8",
91
93
  "@release-it/conventional-changelog": "^10.0.1",
92
94
  "@types/body-scroll-lock": "^3.1.2",
93
95
  "@types/lodash-es": "^4.17.12",
94
96
  "@types/markdown-it": "^14.1.2",
95
- "@types/node": "^24.0.1",
96
- "@vitejs/plugin-vue": "^5.2.4",
97
- "@vitest/coverage-v8": "^3.2.3",
98
- "@vue/reactivity": "^3.5.16",
97
+ "@types/node": "^24.3.0",
98
+ "@vitejs/plugin-vue": "^6.0.1",
99
+ "@vitest/coverage-v8": "^3.2.4",
100
+ "@vue/reactivity": "^3.5.18",
99
101
  "@vue/test-utils": "^2.4.6",
100
102
  "@vuelidate/core": "^2.0.3",
101
103
  "@vuelidate/validators": "^2.0.4",
@@ -110,17 +112,17 @@
110
112
  "markdown-it": "^14.1.0",
111
113
  "normalize.css": "^8.0.1",
112
114
  "pinia": "^3.0.3",
113
- "postcss": "^8.5.5",
115
+ "postcss": "^8.5.6",
114
116
  "postcss-nested": "^7.0.2",
115
117
  "punycode": "^2.3.1",
116
- "release-it": "^19.0.3",
117
- "typescript": "~5.8.3",
118
+ "release-it": "^19.0.4",
119
+ "typescript": "~5.9.2",
118
120
  "v-calendar": "3.0.1",
119
121
  "vite": "^6.3.5",
120
- "vitepress": "^2.0.0-alpha.6",
121
- "vitest": "^3.2.3",
122
- "vue": "^3.5.16",
122
+ "vitepress": "^2.0.0-alpha.11",
123
+ "vitest": "^3.2.4",
124
+ "vue": "^3.5.18",
123
125
  "vue-router": "^4.5.1",
124
- "vue-tsc": "^3.0.4"
126
+ "vue-tsc": "^3.0.5"
125
127
  }
126
128
  }
@@ -1,18 +0,0 @@
1
- import { type Lang, useBrowserLang } from 'sefirot/composables/Lang'
2
- import { type HttpOptions, useHttpConfig } from 'sefirot/stores/HttpConfig'
3
-
4
- export interface HasLang {
5
- lang: Lang
6
- }
7
-
8
- export function useSetupHttp(): (user?: HasLang | null, options?: HttpOptions) => void {
9
- const browserLang = useBrowserLang()
10
- const httpConfig = useHttpConfig()
11
-
12
- return (user, options = {}) => {
13
- httpConfig.apply({
14
- lang: user?.lang ?? browserLang,
15
- ...options
16
- })
17
- }
18
- }