@bstage-sdk/react 0.1.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/LICENSE +21 -0
- package/dist/index.cjs +432 -0
- package/dist/index.d.cts +315 -0
- package/dist/index.d.ts +315 -0
- package/dist/index.js +402 -0
- package/package.json +52 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentType, ReactNode, ReactElement } from 'react';
|
|
3
|
+
import { SlotIdV2, TemplateOptions, PlatformBridge, PlatformEventType, PlatformEventHandler, SlotContextOf, LanguageCode, LocaleTarget, TranslateParams as TranslateParams$1, TranslationKey } from '@bstage-sdk/core';
|
|
4
|
+
export { LocaleTarget } from '@bstage-sdk/core';
|
|
5
|
+
|
|
6
|
+
/** createTemplate이 생성하는 메타데이터. 빌드 파이프라인이 산출물 경로를 정하는 데 사용한다. */
|
|
7
|
+
interface BstageMeta {
|
|
8
|
+
name: string;
|
|
9
|
+
/** Custom Element 태그명. `name`과 동일. `customElements.define`이 사용하는 식별자. */
|
|
10
|
+
elementName: string;
|
|
11
|
+
framework: string;
|
|
12
|
+
/** 위젯이 들어갈 슬롯 id. 페이지에는 없다. */
|
|
13
|
+
slot?: SlotIdV2;
|
|
14
|
+
type?: string;
|
|
15
|
+
}
|
|
16
|
+
/** {@link createTemplate} 옵션. name 필수. */
|
|
17
|
+
interface CreateTemplateOptions extends Omit<TemplateOptions, 'slot'> {
|
|
18
|
+
/**
|
|
19
|
+
* 이 위젯이 들어갈 슬롯 id. `src/slots/` 아래 템플릿만 지정한다.
|
|
20
|
+
*
|
|
21
|
+
* 카탈로그(`SLOT_CATALOG_V2`)의 id로 좁혀 두어 편집기에서 자동완성이 뜬다.
|
|
22
|
+
* 페이지(`src/pages/`)는 폴더 구조가 배포 경로를 정하므로 이 옵션을 쓰지 않는다.
|
|
23
|
+
*/
|
|
24
|
+
slot?: SlotIdV2;
|
|
25
|
+
/** Shadow DOM에 주입할 inline CSS 문자열. `index.css?inline` import 값을 전달한다. */
|
|
26
|
+
styles?: string;
|
|
27
|
+
}
|
|
28
|
+
/** bstage 메타데이터가 첨부된 React 컴포넌트. `<Template />` 형태로 직접 렌더링 가능. */
|
|
29
|
+
type BstageTemplateComponent<P = any> = ComponentType<P> & {
|
|
30
|
+
__bstage_meta__: BstageMeta;
|
|
31
|
+
__bstage_options__: CreateTemplateOptions;
|
|
32
|
+
__bstage_inner__: ComponentType<P>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @internal 빌드 파이프라인 전용. 직접 사용하지 마세요.
|
|
36
|
+
*/
|
|
37
|
+
declare const __bstage_registry__: Set<BstageTemplateComponent<any>>;
|
|
38
|
+
/**
|
|
39
|
+
* React 컴포넌트로부터 bstage 템플릿 컴포넌트를 생성한다.
|
|
40
|
+
*
|
|
41
|
+
* bstage 메타데이터가 첨부된 React 컴포넌트를 반환.
|
|
42
|
+
* WC 등록은 빌드 파이프라인에서 별도로 처리.
|
|
43
|
+
*/
|
|
44
|
+
declare function createTemplate(Component: ComponentType<any>, options: CreateTemplateOptions): BstageTemplateComponent;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @internal 빌드 파이프라인 전용. 직접 사용하지 마세요.
|
|
48
|
+
*/
|
|
49
|
+
declare function registerTemplate(template: BstageTemplateComponent): typeof HTMLElement;
|
|
50
|
+
|
|
51
|
+
/** bstage 템플릿 컨텍스트 값. PlatformBridge를 포함. */
|
|
52
|
+
interface BstageContextValue {
|
|
53
|
+
bridge: PlatformBridge;
|
|
54
|
+
}
|
|
55
|
+
/** @internal 프레임워크 어댑터가 Provider로 감싸는 데 사용. */
|
|
56
|
+
declare const BstageContext: react.Context<BstageContextValue | null>;
|
|
57
|
+
/**
|
|
58
|
+
* PlatformBridge와 BstageClient에 접근하는 hook.
|
|
59
|
+
* createTemplate으로 감싼 컴포넌트 내부에서만 사용 가능.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* const { bridge } = useBstageContext()
|
|
64
|
+
* bridge.emit('navigate', { path: '/profile' })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function useBstageContext(): BstageContextValue;
|
|
68
|
+
|
|
69
|
+
/** useNavigation이 반환하는 네비게이션 함수 모음. */
|
|
70
|
+
interface NavigationActions {
|
|
71
|
+
/** 앱 내 경로로 이동. */
|
|
72
|
+
navigate: (path: string, params?: Record<string, string>) => void;
|
|
73
|
+
/** 이전 화면으로 돌아가기. */
|
|
74
|
+
goBack: () => void;
|
|
75
|
+
/** 외부 URL을 새 탭으로 열기. */
|
|
76
|
+
openExternal: (url: string) => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 플랫폼 네비게이션 hook.
|
|
80
|
+
*
|
|
81
|
+
* 플랫폼에 임베드된 상태에서는 PlatformBridge를 통해 네비게이션하고,
|
|
82
|
+
* 로컬 dev 환경 등 BstageContext가 없을 때는 브라우저 네이티브 API로 fallback한다.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* const { navigate, goBack, openExternal } = useNavigation()
|
|
87
|
+
* navigate('/profile', { userId: '123' })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function useNavigation(): NavigationActions;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 플랫폼 → 템플릿 이벤트를 구독하는 hook.
|
|
94
|
+
*
|
|
95
|
+
* 컴포넌트 마운트 시 구독하고, 언마운트 시 자동 해제한다.
|
|
96
|
+
* BstageContext가 없는 환경(로컬 dev 등)에서는 아무 동작도 하지 않는다.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```tsx
|
|
100
|
+
* usePlatformEvent('slot.init', (payload) => {
|
|
101
|
+
* setResourceId(payload.resourceId)
|
|
102
|
+
* })
|
|
103
|
+
*
|
|
104
|
+
* usePlatformEvent('ticket.create.after', ({ ticketId, productId }) => {
|
|
105
|
+
* saveCustomField(ticketId)
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
declare function usePlatformEvent<T extends PlatformEventType>(type: T, handler: PlatformEventHandler<T>): void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 호스트가 마운트 시점에 한 번 dispatch한 슬롯 context를 받는 hook.
|
|
113
|
+
*
|
|
114
|
+
* 위젯이 ready 신호를 보내기 전에 호스트가 dispatch했어도 `TemplateHandle`의 버퍼링이
|
|
115
|
+
* ready 시점까지 잡고 있다가 자동 replay하므로, 위젯 입장에서는 마운트 후 자연스럽게 한 번 받는다.
|
|
116
|
+
*
|
|
117
|
+
* 호스트 → 위젯 단방향 read-only (결정-016·022). 마운트 이후 호스트가 데이터 변경해도
|
|
118
|
+
* 위젯에 다시 보내지 않으니, 위젯은 받은 값으로 자기 lifecycle을 산다.
|
|
119
|
+
*
|
|
120
|
+
* 처음 받기 전(또는 호스트가 안 보낸 경우) `undefined`. 위젯 측에서 가드 필요.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { createTemplate, useSlotContext } from '@bstage-sdk/react'
|
|
125
|
+
*
|
|
126
|
+
* const MyQrWidget = () => {
|
|
127
|
+
* const context = useSlotContext<'admin.digital-ticket-detail.form:after'>()
|
|
128
|
+
* if (!context) return null
|
|
129
|
+
* return <QrPanel ticket={context.ticket} />
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* export default createTemplate(MyQrWidget, { name: 'my-qr-widget' })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function useSlotContext<Id extends SlotIdV2>(): SlotContextOf<Id> | undefined;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 반환한 ref를 붙인 엘리먼트의 ShadowRoot에 CSS를 주입한다.
|
|
139
|
+
*
|
|
140
|
+
* `createTemplate`의 `styles` 옵션이 템플릿 전체 스타일을 등록 시점에 한 번 넣는 것과 달리,
|
|
141
|
+
* 이 훅은 렌더 중에(조건부·컴포넌트 단위로) 넣는다. 같은 CSS는 해시로 한 번만 들어간다.
|
|
142
|
+
*/
|
|
143
|
+
declare function useShadowStyle<T extends HTMLElement = HTMLElement>(css: string): react.RefObject<T>;
|
|
144
|
+
|
|
145
|
+
interface LocaleState {
|
|
146
|
+
/** 현재 렌더 로케일. 모드별 신호 우선순위로 판정한다. */
|
|
147
|
+
current: LanguageCode;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 현재 렌더 로케일을 구독하는 hook. 플랫폼이 리로드 없이 언어를 바꿔도(SPA 전환) reactive하게 갱신된다.
|
|
151
|
+
*
|
|
152
|
+
* 리액티브 신호는 `<html lang>`(MutationObserver로 관찰)이며, 대상에 따라 실제 값의 우선순위가 다르다.
|
|
153
|
+
* 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다(생략 시 `'user'`).
|
|
154
|
+
* - `'user'`(기본): `<html lang>` → 쿠키 `bmf_bstage_lang`. 유저 플랫폼가 언어 변경 시 `<html lang>`을
|
|
155
|
+
* 갱신하므로 플랫폼 추가 작업 없이 동작한다.
|
|
156
|
+
* - `'admin'`: 쿠키 `bmf_mybstage_locale` → `<html lang>`. 어드민 임베드 템플릿에서 쓴다.
|
|
157
|
+
*
|
|
158
|
+
* `BstageLocaleProvider` 밖에서 호출하면 throw한다. 신호가 없는 환경에서는 기본 로케일로 fallback한다.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* import { useLocale } from '@bstage-sdk/react'
|
|
163
|
+
*
|
|
164
|
+
* const Greeting = () => {
|
|
165
|
+
* const { current } = useLocale()
|
|
166
|
+
* return <p>현재 언어: {current}</p>
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function useLocale(): LocaleState;
|
|
171
|
+
|
|
172
|
+
interface BstageLocaleProviderProps {
|
|
173
|
+
/**
|
|
174
|
+
* 하위 트리의 로케일 신호 대상. 생략하면 `'user'`.
|
|
175
|
+
*
|
|
176
|
+
* - `'user'`(기본): 유저 플랫폼. `<html lang>` → `bmf_bstage_lang` 쿠키.
|
|
177
|
+
* - `'admin'`: 어드민 임베드. `bmf_mybstage_locale` 쿠키 → `<html lang>`.
|
|
178
|
+
*/
|
|
179
|
+
target?: LocaleTarget;
|
|
180
|
+
children?: ReactNode;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 하위 트리의 로케일 훅(`useLocale`/`useMessages`/`useBstageTranslations`)이 어떤 대상으로
|
|
184
|
+
* 현재 로케일을 읽을지 결정하는 Provider. **모든 템플릿이 감싸야 한다**(훅은 Provider 밖에서 throw).
|
|
185
|
+
*
|
|
186
|
+
* 어드민 임베드 템플릿은 `<html lang>`이 SSR 기본값으로 고정(런타임 미갱신)이라 신뢰할 수 없고,
|
|
187
|
+
* 런타임 로케일의 진실은 `bmf_mybstage_locale` 쿠키다. 어드민은 `target="admin"`을 넘기고,
|
|
188
|
+
* 유저단은 생략(`'user'`)한다.
|
|
189
|
+
*
|
|
190
|
+
* 훅은 **이 Provider의 하위에서** 호출해야 적용된다(같은 컴포넌트의 return에서 감싸는 경우,
|
|
191
|
+
* 훅을 쓰는 부분을 자식 컴포넌트로 분리한다).
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* import { BstageLocaleProvider, useBstageTranslations } from '@bstage-sdk/react'
|
|
196
|
+
*
|
|
197
|
+
* const Body = () => {
|
|
198
|
+
* const { t } = useBstageTranslations()
|
|
199
|
+
* return <button>{t('A00001')}</button>
|
|
200
|
+
* }
|
|
201
|
+
*
|
|
202
|
+
* // 어드민 템플릿
|
|
203
|
+
* const AdminWidget = () => (
|
|
204
|
+
* <BstageLocaleProvider target="admin">
|
|
205
|
+
* <Body />
|
|
206
|
+
* </BstageLocaleProvider>
|
|
207
|
+
* )
|
|
208
|
+
*
|
|
209
|
+
* // 유저 템플릿 — target 생략
|
|
210
|
+
* const UserWidget = () => (
|
|
211
|
+
* <BstageLocaleProvider>
|
|
212
|
+
* <Body />
|
|
213
|
+
* </BstageLocaleProvider>
|
|
214
|
+
* )
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare function BstageLocaleProvider({ target, children, }: BstageLocaleProviderProps): ReactNode;
|
|
218
|
+
|
|
219
|
+
/** 로케일별 메시지 사전. 키는 개발자가 명명하고, 값은 문자열(보간 토큰 포함 가능). */
|
|
220
|
+
type Messages = Partial<Record<LanguageCode, Record<string, string>>>;
|
|
221
|
+
/** `t()`에 넘기는 보간 파라미터. `{{name}}` 토큰을 치환한다. */
|
|
222
|
+
type TranslateParams = Record<string, string | number>;
|
|
223
|
+
/** union 멤버별로 `keyof`를 분배해, 모든 로케일에 정의된 키의 합집합을 구한다. */
|
|
224
|
+
type DistributeKeys<T> = T extends unknown ? keyof T : never;
|
|
225
|
+
/** 주어진 메시지 사전에서 사용 가능한 키 union (자동완성·타입체크용). */
|
|
226
|
+
type MessageKey<M extends Messages> = Extract<DistributeKeys<M[keyof M]>, string>;
|
|
227
|
+
/**
|
|
228
|
+
* 플랫폼 번역 시스템에 없는 템플릿 자체 문구를 로컬 코드로 다국어 등록하는 hook.
|
|
229
|
+
*
|
|
230
|
+
* 로케일별 메시지 객체를 넘기면 `useLocale().current`에 자동 바인딩된 `t()`를 돌려준다.
|
|
231
|
+
* 키 타입은 객체 리터럴에서 TS가 추론하므로 별도 codegen 없이 자동완성·타입체크가 된다.
|
|
232
|
+
*
|
|
233
|
+
* 현재 로케일에 사전이 없으면 `DEFAULT_LANGUAGE` → 첫 사전 순으로 fallback하고,
|
|
234
|
+
* 키가 없으면 키 문자열을 그대로 돌려준다. 완전 로컬이라 네트워크·플랫폼과 무관하게 동작한다.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```tsx
|
|
238
|
+
* import { useMessages } from '@bstage-sdk/react'
|
|
239
|
+
*
|
|
240
|
+
* const messages = {
|
|
241
|
+
* ko: { scanQr: 'QR을 스캔하세요', greet: '안녕 {{name}}' },
|
|
242
|
+
* en: { scanQr: 'Scan the QR', greet: 'Hi {{name}}' },
|
|
243
|
+
* }
|
|
244
|
+
*
|
|
245
|
+
* const Greeting = () => {
|
|
246
|
+
* const t = useMessages(messages)
|
|
247
|
+
* return <p>{t('greet', { name: '쇼' })}</p>
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* 로케일 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다. 어드민 임베드 템플릿은
|
|
252
|
+
* 훅 호출부를 `<BstageLocaleProvider target="admin">`로 감싼다(유저는 생략). Provider 밖이면 throw.
|
|
253
|
+
*/
|
|
254
|
+
declare function useMessages<const M extends Messages>(messages: M): (key: MessageKey<M>, params?: TranslateParams) => string;
|
|
255
|
+
|
|
256
|
+
/** `tNode`에 넘기는 옵션. */
|
|
257
|
+
interface TranslateNodeOptions {
|
|
258
|
+
/** `{{token}}` 보간 파라미터. */
|
|
259
|
+
params?: TranslateParams$1;
|
|
260
|
+
/**
|
|
261
|
+
* `<N>…</N>` 조각을 감쌀 엘리먼트. 키가 태그 인덱스다.
|
|
262
|
+
*
|
|
263
|
+
* 넘기지 않은 인덱스는 감싸지 않고 내용만 렌더한다(문구가 사라지지 않는다).
|
|
264
|
+
*/
|
|
265
|
+
tags?: Record<number, ReactElement>;
|
|
266
|
+
}
|
|
267
|
+
interface UseBstageTranslationsResult {
|
|
268
|
+
/** 현재 렌더 로케일 코드. `useLocale().current`와 동일하다(편의상 함께 제공). */
|
|
269
|
+
current: LanguageCode;
|
|
270
|
+
/** 현재 로케일의 플랫폼 번역 키를 해석한다. 로드 전(또는 실패 시)엔 키 문자열을 그대로 반환. */
|
|
271
|
+
t: (key: TranslationKey, params?: TranslateParams$1) => string;
|
|
272
|
+
/**
|
|
273
|
+
* `<0>…</0>` 리치텍스트가 있는 문구를 React 노드로 렌더한다.
|
|
274
|
+
*
|
|
275
|
+
* `t`는 문자열을 반환하므로 태그가 글자로 보인다 — 링크·강조가 든 문구는 이쪽을 쓴다.
|
|
276
|
+
* 문자열이 필요한 자리(placeholder·aria-label)는 계속 `t`를 쓴다.
|
|
277
|
+
*/
|
|
278
|
+
tNode: (key: TranslationKey, options?: TranslateNodeOptions) => ReactNode;
|
|
279
|
+
/** 사전 로드 완료 여부. `false` 동안 `t`는 키 문자열을 반환하므로 필요하면 렌더를 가드한다. */
|
|
280
|
+
ready: boolean;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* 플랫폼의 공용 번역 사전(`Bxxxxx` → 문자열)을 재사용하는 hook.
|
|
284
|
+
*
|
|
285
|
+
* 현재 로케일(`current`)의 사전을 TMS가 배포한 CDN에서 가져와(`fetchTranslations`) `t(key)`로
|
|
286
|
+
* 해석한다. 사전 시스템(`user`/`admin`)은 `BstageLocaleProvider`의 `target`이 정한다. 로케일이
|
|
287
|
+
* 바뀌면 해당 로케일 사전을 다시 가져온다(캐시되어 빠름). `{{token}}` 보간을 지원한다.
|
|
288
|
+
*
|
|
289
|
+
* **미번역 폴백** — 사전에는 키는 있고 값만 빈 문자열인 항목이 있다(어드민은 일부 로케일이 대부분 그렇다).
|
|
290
|
+
* 그런 키를 만나면 폴백 사전(기본 `en` → `ko`)을 **그때 추가로 받아** 값을 채운다. 번역이 다 있는
|
|
291
|
+
* 로케일에서는 추가 요청이 일어나지 않는다.
|
|
292
|
+
*
|
|
293
|
+
* 현재 언어 코드(`current`)도 함께 반환하므로, 플랫폼 문구를 쓰는 위젯은 이 hook 하나로
|
|
294
|
+
* 언어·번역을 모두 얻는다. 언어 코드만 필요하면 fetch가 없는 `useLocale()`을 쓴다.
|
|
295
|
+
*
|
|
296
|
+
* 키가 opaque(`B00001`)이므로 타입 안전은 `bstage i18n` codegen이 채운다(미생성 시 `string`).
|
|
297
|
+
* 템플릿 자체 문구는 `useMessages`를 쓴다 — 이 hook은 플랫폼 문구 재사용 전용이다.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```tsx
|
|
301
|
+
* import { useBstageTranslations } from '@bstage-sdk/react'
|
|
302
|
+
*
|
|
303
|
+
* const ApplyButton = () => {
|
|
304
|
+
* const { t, ready } = useBstageTranslations()
|
|
305
|
+
* if (!ready) return null
|
|
306
|
+
* return <button>{t('B00001')}</button>
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* 로케일 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다. 어드민 임베드 템플릿은
|
|
311
|
+
* 훅 호출부를 `<BstageLocaleProvider target="admin">`로 감싼다(유저는 생략). Provider 밖이면 throw.
|
|
312
|
+
*/
|
|
313
|
+
declare function useBstageTranslations(): UseBstageTranslationsResult;
|
|
314
|
+
|
|
315
|
+
export { BstageContext, type BstageContextValue, BstageLocaleProvider, type BstageLocaleProviderProps, type BstageMeta, type BstageTemplateComponent, type CreateTemplateOptions, type LocaleState, type MessageKey, type Messages, type NavigationActions, type TranslateNodeOptions, type TranslateParams, type UseBstageTranslationsResult, __bstage_registry__, createTemplate, registerTemplate, useBstageContext, useBstageTranslations, useLocale, useMessages, useNavigation, usePlatformEvent, useShadowStyle, useSlotContext };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentType, ReactNode, ReactElement } from 'react';
|
|
3
|
+
import { SlotIdV2, TemplateOptions, PlatformBridge, PlatformEventType, PlatformEventHandler, SlotContextOf, LanguageCode, LocaleTarget, TranslateParams as TranslateParams$1, TranslationKey } from '@bstage-sdk/core';
|
|
4
|
+
export { LocaleTarget } from '@bstage-sdk/core';
|
|
5
|
+
|
|
6
|
+
/** createTemplate이 생성하는 메타데이터. 빌드 파이프라인이 산출물 경로를 정하는 데 사용한다. */
|
|
7
|
+
interface BstageMeta {
|
|
8
|
+
name: string;
|
|
9
|
+
/** Custom Element 태그명. `name`과 동일. `customElements.define`이 사용하는 식별자. */
|
|
10
|
+
elementName: string;
|
|
11
|
+
framework: string;
|
|
12
|
+
/** 위젯이 들어갈 슬롯 id. 페이지에는 없다. */
|
|
13
|
+
slot?: SlotIdV2;
|
|
14
|
+
type?: string;
|
|
15
|
+
}
|
|
16
|
+
/** {@link createTemplate} 옵션. name 필수. */
|
|
17
|
+
interface CreateTemplateOptions extends Omit<TemplateOptions, 'slot'> {
|
|
18
|
+
/**
|
|
19
|
+
* 이 위젯이 들어갈 슬롯 id. `src/slots/` 아래 템플릿만 지정한다.
|
|
20
|
+
*
|
|
21
|
+
* 카탈로그(`SLOT_CATALOG_V2`)의 id로 좁혀 두어 편집기에서 자동완성이 뜬다.
|
|
22
|
+
* 페이지(`src/pages/`)는 폴더 구조가 배포 경로를 정하므로 이 옵션을 쓰지 않는다.
|
|
23
|
+
*/
|
|
24
|
+
slot?: SlotIdV2;
|
|
25
|
+
/** Shadow DOM에 주입할 inline CSS 문자열. `index.css?inline` import 값을 전달한다. */
|
|
26
|
+
styles?: string;
|
|
27
|
+
}
|
|
28
|
+
/** bstage 메타데이터가 첨부된 React 컴포넌트. `<Template />` 형태로 직접 렌더링 가능. */
|
|
29
|
+
type BstageTemplateComponent<P = any> = ComponentType<P> & {
|
|
30
|
+
__bstage_meta__: BstageMeta;
|
|
31
|
+
__bstage_options__: CreateTemplateOptions;
|
|
32
|
+
__bstage_inner__: ComponentType<P>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @internal 빌드 파이프라인 전용. 직접 사용하지 마세요.
|
|
36
|
+
*/
|
|
37
|
+
declare const __bstage_registry__: Set<BstageTemplateComponent<any>>;
|
|
38
|
+
/**
|
|
39
|
+
* React 컴포넌트로부터 bstage 템플릿 컴포넌트를 생성한다.
|
|
40
|
+
*
|
|
41
|
+
* bstage 메타데이터가 첨부된 React 컴포넌트를 반환.
|
|
42
|
+
* WC 등록은 빌드 파이프라인에서 별도로 처리.
|
|
43
|
+
*/
|
|
44
|
+
declare function createTemplate(Component: ComponentType<any>, options: CreateTemplateOptions): BstageTemplateComponent;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @internal 빌드 파이프라인 전용. 직접 사용하지 마세요.
|
|
48
|
+
*/
|
|
49
|
+
declare function registerTemplate(template: BstageTemplateComponent): typeof HTMLElement;
|
|
50
|
+
|
|
51
|
+
/** bstage 템플릿 컨텍스트 값. PlatformBridge를 포함. */
|
|
52
|
+
interface BstageContextValue {
|
|
53
|
+
bridge: PlatformBridge;
|
|
54
|
+
}
|
|
55
|
+
/** @internal 프레임워크 어댑터가 Provider로 감싸는 데 사용. */
|
|
56
|
+
declare const BstageContext: react.Context<BstageContextValue | null>;
|
|
57
|
+
/**
|
|
58
|
+
* PlatformBridge와 BstageClient에 접근하는 hook.
|
|
59
|
+
* createTemplate으로 감싼 컴포넌트 내부에서만 사용 가능.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* const { bridge } = useBstageContext()
|
|
64
|
+
* bridge.emit('navigate', { path: '/profile' })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function useBstageContext(): BstageContextValue;
|
|
68
|
+
|
|
69
|
+
/** useNavigation이 반환하는 네비게이션 함수 모음. */
|
|
70
|
+
interface NavigationActions {
|
|
71
|
+
/** 앱 내 경로로 이동. */
|
|
72
|
+
navigate: (path: string, params?: Record<string, string>) => void;
|
|
73
|
+
/** 이전 화면으로 돌아가기. */
|
|
74
|
+
goBack: () => void;
|
|
75
|
+
/** 외부 URL을 새 탭으로 열기. */
|
|
76
|
+
openExternal: (url: string) => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 플랫폼 네비게이션 hook.
|
|
80
|
+
*
|
|
81
|
+
* 플랫폼에 임베드된 상태에서는 PlatformBridge를 통해 네비게이션하고,
|
|
82
|
+
* 로컬 dev 환경 등 BstageContext가 없을 때는 브라우저 네이티브 API로 fallback한다.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* const { navigate, goBack, openExternal } = useNavigation()
|
|
87
|
+
* navigate('/profile', { userId: '123' })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function useNavigation(): NavigationActions;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 플랫폼 → 템플릿 이벤트를 구독하는 hook.
|
|
94
|
+
*
|
|
95
|
+
* 컴포넌트 마운트 시 구독하고, 언마운트 시 자동 해제한다.
|
|
96
|
+
* BstageContext가 없는 환경(로컬 dev 등)에서는 아무 동작도 하지 않는다.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```tsx
|
|
100
|
+
* usePlatformEvent('slot.init', (payload) => {
|
|
101
|
+
* setResourceId(payload.resourceId)
|
|
102
|
+
* })
|
|
103
|
+
*
|
|
104
|
+
* usePlatformEvent('ticket.create.after', ({ ticketId, productId }) => {
|
|
105
|
+
* saveCustomField(ticketId)
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
declare function usePlatformEvent<T extends PlatformEventType>(type: T, handler: PlatformEventHandler<T>): void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 호스트가 마운트 시점에 한 번 dispatch한 슬롯 context를 받는 hook.
|
|
113
|
+
*
|
|
114
|
+
* 위젯이 ready 신호를 보내기 전에 호스트가 dispatch했어도 `TemplateHandle`의 버퍼링이
|
|
115
|
+
* ready 시점까지 잡고 있다가 자동 replay하므로, 위젯 입장에서는 마운트 후 자연스럽게 한 번 받는다.
|
|
116
|
+
*
|
|
117
|
+
* 호스트 → 위젯 단방향 read-only (결정-016·022). 마운트 이후 호스트가 데이터 변경해도
|
|
118
|
+
* 위젯에 다시 보내지 않으니, 위젯은 받은 값으로 자기 lifecycle을 산다.
|
|
119
|
+
*
|
|
120
|
+
* 처음 받기 전(또는 호스트가 안 보낸 경우) `undefined`. 위젯 측에서 가드 필요.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { createTemplate, useSlotContext } from '@bstage-sdk/react'
|
|
125
|
+
*
|
|
126
|
+
* const MyQrWidget = () => {
|
|
127
|
+
* const context = useSlotContext<'admin.digital-ticket-detail.form:after'>()
|
|
128
|
+
* if (!context) return null
|
|
129
|
+
* return <QrPanel ticket={context.ticket} />
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* export default createTemplate(MyQrWidget, { name: 'my-qr-widget' })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function useSlotContext<Id extends SlotIdV2>(): SlotContextOf<Id> | undefined;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 반환한 ref를 붙인 엘리먼트의 ShadowRoot에 CSS를 주입한다.
|
|
139
|
+
*
|
|
140
|
+
* `createTemplate`의 `styles` 옵션이 템플릿 전체 스타일을 등록 시점에 한 번 넣는 것과 달리,
|
|
141
|
+
* 이 훅은 렌더 중에(조건부·컴포넌트 단위로) 넣는다. 같은 CSS는 해시로 한 번만 들어간다.
|
|
142
|
+
*/
|
|
143
|
+
declare function useShadowStyle<T extends HTMLElement = HTMLElement>(css: string): react.RefObject<T>;
|
|
144
|
+
|
|
145
|
+
interface LocaleState {
|
|
146
|
+
/** 현재 렌더 로케일. 모드별 신호 우선순위로 판정한다. */
|
|
147
|
+
current: LanguageCode;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 현재 렌더 로케일을 구독하는 hook. 플랫폼이 리로드 없이 언어를 바꿔도(SPA 전환) reactive하게 갱신된다.
|
|
151
|
+
*
|
|
152
|
+
* 리액티브 신호는 `<html lang>`(MutationObserver로 관찰)이며, 대상에 따라 실제 값의 우선순위가 다르다.
|
|
153
|
+
* 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다(생략 시 `'user'`).
|
|
154
|
+
* - `'user'`(기본): `<html lang>` → 쿠키 `bmf_bstage_lang`. 유저 플랫폼가 언어 변경 시 `<html lang>`을
|
|
155
|
+
* 갱신하므로 플랫폼 추가 작업 없이 동작한다.
|
|
156
|
+
* - `'admin'`: 쿠키 `bmf_mybstage_locale` → `<html lang>`. 어드민 임베드 템플릿에서 쓴다.
|
|
157
|
+
*
|
|
158
|
+
* `BstageLocaleProvider` 밖에서 호출하면 throw한다. 신호가 없는 환경에서는 기본 로케일로 fallback한다.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* import { useLocale } from '@bstage-sdk/react'
|
|
163
|
+
*
|
|
164
|
+
* const Greeting = () => {
|
|
165
|
+
* const { current } = useLocale()
|
|
166
|
+
* return <p>현재 언어: {current}</p>
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function useLocale(): LocaleState;
|
|
171
|
+
|
|
172
|
+
interface BstageLocaleProviderProps {
|
|
173
|
+
/**
|
|
174
|
+
* 하위 트리의 로케일 신호 대상. 생략하면 `'user'`.
|
|
175
|
+
*
|
|
176
|
+
* - `'user'`(기본): 유저 플랫폼. `<html lang>` → `bmf_bstage_lang` 쿠키.
|
|
177
|
+
* - `'admin'`: 어드민 임베드. `bmf_mybstage_locale` 쿠키 → `<html lang>`.
|
|
178
|
+
*/
|
|
179
|
+
target?: LocaleTarget;
|
|
180
|
+
children?: ReactNode;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 하위 트리의 로케일 훅(`useLocale`/`useMessages`/`useBstageTranslations`)이 어떤 대상으로
|
|
184
|
+
* 현재 로케일을 읽을지 결정하는 Provider. **모든 템플릿이 감싸야 한다**(훅은 Provider 밖에서 throw).
|
|
185
|
+
*
|
|
186
|
+
* 어드민 임베드 템플릿은 `<html lang>`이 SSR 기본값으로 고정(런타임 미갱신)이라 신뢰할 수 없고,
|
|
187
|
+
* 런타임 로케일의 진실은 `bmf_mybstage_locale` 쿠키다. 어드민은 `target="admin"`을 넘기고,
|
|
188
|
+
* 유저단은 생략(`'user'`)한다.
|
|
189
|
+
*
|
|
190
|
+
* 훅은 **이 Provider의 하위에서** 호출해야 적용된다(같은 컴포넌트의 return에서 감싸는 경우,
|
|
191
|
+
* 훅을 쓰는 부분을 자식 컴포넌트로 분리한다).
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* import { BstageLocaleProvider, useBstageTranslations } from '@bstage-sdk/react'
|
|
196
|
+
*
|
|
197
|
+
* const Body = () => {
|
|
198
|
+
* const { t } = useBstageTranslations()
|
|
199
|
+
* return <button>{t('A00001')}</button>
|
|
200
|
+
* }
|
|
201
|
+
*
|
|
202
|
+
* // 어드민 템플릿
|
|
203
|
+
* const AdminWidget = () => (
|
|
204
|
+
* <BstageLocaleProvider target="admin">
|
|
205
|
+
* <Body />
|
|
206
|
+
* </BstageLocaleProvider>
|
|
207
|
+
* )
|
|
208
|
+
*
|
|
209
|
+
* // 유저 템플릿 — target 생략
|
|
210
|
+
* const UserWidget = () => (
|
|
211
|
+
* <BstageLocaleProvider>
|
|
212
|
+
* <Body />
|
|
213
|
+
* </BstageLocaleProvider>
|
|
214
|
+
* )
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare function BstageLocaleProvider({ target, children, }: BstageLocaleProviderProps): ReactNode;
|
|
218
|
+
|
|
219
|
+
/** 로케일별 메시지 사전. 키는 개발자가 명명하고, 값은 문자열(보간 토큰 포함 가능). */
|
|
220
|
+
type Messages = Partial<Record<LanguageCode, Record<string, string>>>;
|
|
221
|
+
/** `t()`에 넘기는 보간 파라미터. `{{name}}` 토큰을 치환한다. */
|
|
222
|
+
type TranslateParams = Record<string, string | number>;
|
|
223
|
+
/** union 멤버별로 `keyof`를 분배해, 모든 로케일에 정의된 키의 합집합을 구한다. */
|
|
224
|
+
type DistributeKeys<T> = T extends unknown ? keyof T : never;
|
|
225
|
+
/** 주어진 메시지 사전에서 사용 가능한 키 union (자동완성·타입체크용). */
|
|
226
|
+
type MessageKey<M extends Messages> = Extract<DistributeKeys<M[keyof M]>, string>;
|
|
227
|
+
/**
|
|
228
|
+
* 플랫폼 번역 시스템에 없는 템플릿 자체 문구를 로컬 코드로 다국어 등록하는 hook.
|
|
229
|
+
*
|
|
230
|
+
* 로케일별 메시지 객체를 넘기면 `useLocale().current`에 자동 바인딩된 `t()`를 돌려준다.
|
|
231
|
+
* 키 타입은 객체 리터럴에서 TS가 추론하므로 별도 codegen 없이 자동완성·타입체크가 된다.
|
|
232
|
+
*
|
|
233
|
+
* 현재 로케일에 사전이 없으면 `DEFAULT_LANGUAGE` → 첫 사전 순으로 fallback하고,
|
|
234
|
+
* 키가 없으면 키 문자열을 그대로 돌려준다. 완전 로컬이라 네트워크·플랫폼과 무관하게 동작한다.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```tsx
|
|
238
|
+
* import { useMessages } from '@bstage-sdk/react'
|
|
239
|
+
*
|
|
240
|
+
* const messages = {
|
|
241
|
+
* ko: { scanQr: 'QR을 스캔하세요', greet: '안녕 {{name}}' },
|
|
242
|
+
* en: { scanQr: 'Scan the QR', greet: 'Hi {{name}}' },
|
|
243
|
+
* }
|
|
244
|
+
*
|
|
245
|
+
* const Greeting = () => {
|
|
246
|
+
* const t = useMessages(messages)
|
|
247
|
+
* return <p>{t('greet', { name: '쇼' })}</p>
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* 로케일 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다. 어드민 임베드 템플릿은
|
|
252
|
+
* 훅 호출부를 `<BstageLocaleProvider target="admin">`로 감싼다(유저는 생략). Provider 밖이면 throw.
|
|
253
|
+
*/
|
|
254
|
+
declare function useMessages<const M extends Messages>(messages: M): (key: MessageKey<M>, params?: TranslateParams) => string;
|
|
255
|
+
|
|
256
|
+
/** `tNode`에 넘기는 옵션. */
|
|
257
|
+
interface TranslateNodeOptions {
|
|
258
|
+
/** `{{token}}` 보간 파라미터. */
|
|
259
|
+
params?: TranslateParams$1;
|
|
260
|
+
/**
|
|
261
|
+
* `<N>…</N>` 조각을 감쌀 엘리먼트. 키가 태그 인덱스다.
|
|
262
|
+
*
|
|
263
|
+
* 넘기지 않은 인덱스는 감싸지 않고 내용만 렌더한다(문구가 사라지지 않는다).
|
|
264
|
+
*/
|
|
265
|
+
tags?: Record<number, ReactElement>;
|
|
266
|
+
}
|
|
267
|
+
interface UseBstageTranslationsResult {
|
|
268
|
+
/** 현재 렌더 로케일 코드. `useLocale().current`와 동일하다(편의상 함께 제공). */
|
|
269
|
+
current: LanguageCode;
|
|
270
|
+
/** 현재 로케일의 플랫폼 번역 키를 해석한다. 로드 전(또는 실패 시)엔 키 문자열을 그대로 반환. */
|
|
271
|
+
t: (key: TranslationKey, params?: TranslateParams$1) => string;
|
|
272
|
+
/**
|
|
273
|
+
* `<0>…</0>` 리치텍스트가 있는 문구를 React 노드로 렌더한다.
|
|
274
|
+
*
|
|
275
|
+
* `t`는 문자열을 반환하므로 태그가 글자로 보인다 — 링크·강조가 든 문구는 이쪽을 쓴다.
|
|
276
|
+
* 문자열이 필요한 자리(placeholder·aria-label)는 계속 `t`를 쓴다.
|
|
277
|
+
*/
|
|
278
|
+
tNode: (key: TranslationKey, options?: TranslateNodeOptions) => ReactNode;
|
|
279
|
+
/** 사전 로드 완료 여부. `false` 동안 `t`는 키 문자열을 반환하므로 필요하면 렌더를 가드한다. */
|
|
280
|
+
ready: boolean;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* 플랫폼의 공용 번역 사전(`Bxxxxx` → 문자열)을 재사용하는 hook.
|
|
284
|
+
*
|
|
285
|
+
* 현재 로케일(`current`)의 사전을 TMS가 배포한 CDN에서 가져와(`fetchTranslations`) `t(key)`로
|
|
286
|
+
* 해석한다. 사전 시스템(`user`/`admin`)은 `BstageLocaleProvider`의 `target`이 정한다. 로케일이
|
|
287
|
+
* 바뀌면 해당 로케일 사전을 다시 가져온다(캐시되어 빠름). `{{token}}` 보간을 지원한다.
|
|
288
|
+
*
|
|
289
|
+
* **미번역 폴백** — 사전에는 키는 있고 값만 빈 문자열인 항목이 있다(어드민은 일부 로케일이 대부분 그렇다).
|
|
290
|
+
* 그런 키를 만나면 폴백 사전(기본 `en` → `ko`)을 **그때 추가로 받아** 값을 채운다. 번역이 다 있는
|
|
291
|
+
* 로케일에서는 추가 요청이 일어나지 않는다.
|
|
292
|
+
*
|
|
293
|
+
* 현재 언어 코드(`current`)도 함께 반환하므로, 플랫폼 문구를 쓰는 위젯은 이 hook 하나로
|
|
294
|
+
* 언어·번역을 모두 얻는다. 언어 코드만 필요하면 fetch가 없는 `useLocale()`을 쓴다.
|
|
295
|
+
*
|
|
296
|
+
* 키가 opaque(`B00001`)이므로 타입 안전은 `bstage i18n` codegen이 채운다(미생성 시 `string`).
|
|
297
|
+
* 템플릿 자체 문구는 `useMessages`를 쓴다 — 이 hook은 플랫폼 문구 재사용 전용이다.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```tsx
|
|
301
|
+
* import { useBstageTranslations } from '@bstage-sdk/react'
|
|
302
|
+
*
|
|
303
|
+
* const ApplyButton = () => {
|
|
304
|
+
* const { t, ready } = useBstageTranslations()
|
|
305
|
+
* if (!ready) return null
|
|
306
|
+
* return <button>{t('B00001')}</button>
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* 로케일 대상은 `BstageLocaleProvider`(`target` prop)로 결정한다. 어드민 임베드 템플릿은
|
|
311
|
+
* 훅 호출부를 `<BstageLocaleProvider target="admin">`로 감싼다(유저는 생략). Provider 밖이면 throw.
|
|
312
|
+
*/
|
|
313
|
+
declare function useBstageTranslations(): UseBstageTranslationsResult;
|
|
314
|
+
|
|
315
|
+
export { BstageContext, type BstageContextValue, BstageLocaleProvider, type BstageLocaleProviderProps, type BstageMeta, type BstageTemplateComponent, type CreateTemplateOptions, type LocaleState, type MessageKey, type Messages, type NavigationActions, type TranslateNodeOptions, type TranslateParams, type UseBstageTranslationsResult, __bstage_registry__, createTemplate, registerTemplate, useBstageContext, useBstageTranslations, useLocale, useMessages, useNavigation, usePlatformEvent, useShadowStyle, useSlotContext };
|