@besaitech/ng-design-system 0.0.59 → 0.0.61
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/README.md +44 -0
- package/fesm2022/besaitech-ng-design-system.mjs +202 -24
- package/fesm2022/besaitech-ng-design-system.mjs.map +1 -1
- package/index.d.ts +100 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -203,6 +203,50 @@ Import names are the `Sl…` classes; the markup selectors are `sds-…`.
|
|
|
203
203
|
| `SdsTopbar` | `<sds-topbar>` | `appName`, `user`, `(logout)`; `[sdsLogo]` slot |
|
|
204
204
|
| `SdsSidebar` + `SdsNavGroup` + `SdsNavItem` | `<sds-sidebar>` … | Collapsible nav rail; collapse state via root-provided `SidebarStore`; items render `routerLink` or `<button>` |
|
|
205
205
|
|
|
206
|
+
## Theme & cross-app preferences
|
|
207
|
+
|
|
208
|
+
`SdsThemeService` holds the person's **mode** — `'system' | 'light' | 'dark'`, persisted to `localStorage`
|
|
209
|
+
under `sds-theme` — and resolves it to the painted **theme** (`light`/`dark`); `system` follows the OS live.
|
|
210
|
+
`toggle()` / `setTheme()` set an explicit theme, `setMode('system')` goes back to following the OS.
|
|
211
|
+
|
|
212
|
+
Apps of one product can carry the person's language and theme in the URL when they link to each other, so the
|
|
213
|
+
page that opens matches. Sending side:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { appendUiPrefs } from '@besaitech/ng-design-system';
|
|
217
|
+
|
|
218
|
+
appendUiPrefs('https://auth.example/continue#token=abc', { lang: translate.getCurrentLang(), theme: theme.mode() });
|
|
219
|
+
// → https://auth.example/continue?lang=fr&theme=dark#token=abc
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Never put them inside a nested redirect a server matches exactly (`return_to`, `redirect_uri`) — append them to
|
|
223
|
+
the outer URL. Receiving side: an inline script in `<head>` of `index.html` applies, persists and strips them
|
|
224
|
+
**before first paint** (no flash, and no import of this library at the root). `LANG_KEY` is the app's own
|
|
225
|
+
language storage key; keep `LANGS` in step with the app's languages. `readUiPrefs` / `stripUiPrefs` are the same
|
|
226
|
+
logic for code and tests.
|
|
227
|
+
|
|
228
|
+
```html
|
|
229
|
+
<script>
|
|
230
|
+
(function () {
|
|
231
|
+
var LANG_KEY = 'app.lang', LANGS = ['en', 'fr', 'nl'], THEME_KEY = 'sds-theme', MODES = ['system', 'light', 'dark'];
|
|
232
|
+
var url = new URL(location.href), q = url.searchParams, lang = q.get('lang'), mode = q.get('theme');
|
|
233
|
+
try {
|
|
234
|
+
if (LANGS.indexOf(lang) >= 0) localStorage.setItem(LANG_KEY, lang);
|
|
235
|
+
if (MODES.indexOf(mode) >= 0) localStorage.setItem(THEME_KEY, mode);
|
|
236
|
+
} catch (e) {}
|
|
237
|
+
try { lang = localStorage.getItem(LANG_KEY) || lang; mode = localStorage.getItem(THEME_KEY) || mode; } catch (e) {}
|
|
238
|
+
if (LANGS.indexOf(lang) >= 0) document.documentElement.lang = lang;
|
|
239
|
+
var dark = mode === 'dark' || (mode !== 'light' && matchMedia('(prefers-color-scheme: dark)').matches);
|
|
240
|
+
document.documentElement.classList.toggle('dark', dark);
|
|
241
|
+
document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
|
|
242
|
+
if (q.has('lang') || q.has('theme')) {
|
|
243
|
+
q.delete('lang'); q.delete('theme');
|
|
244
|
+
history.replaceState(history.state, '', url.pathname + url.search + url.hash);
|
|
245
|
+
}
|
|
246
|
+
})();
|
|
247
|
+
</script>
|
|
248
|
+
```
|
|
249
|
+
|
|
206
250
|
## Labels & languages
|
|
207
251
|
|
|
208
252
|
The library ships **no translations of its own**. Every visible or spoken string — placeholders,
|
|
@@ -15837,7 +15837,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
15837
15837
|
}]
|
|
15838
15838
|
}], propDecorators: { closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }] } });
|
|
15839
15839
|
|
|
15840
|
-
|
|
15840
|
+
/** The localStorage key the mode is persisted under. Also read by the pre-paint boot script (see README). */
|
|
15841
|
+
const SDS_THEME_STORAGE_KEY = 'sds-theme';
|
|
15842
|
+
/** `true` for the three values {@link SdsThemeMode} accepts — for validating stored or URL-supplied input. */
|
|
15843
|
+
function isSdsThemeMode(value) {
|
|
15844
|
+
return value === 'system' || value === 'light' || value === 'dark';
|
|
15845
|
+
}
|
|
15841
15846
|
/**
|
|
15842
15847
|
* Light/dark theme state for the whole app. It owns exactly one thing: the presence of the `.dark`
|
|
15843
15848
|
* class on the document root, which flips every design token defined under `.dark` in the theme CSS
|
|
@@ -15848,53 +15853,80 @@ const STORAGE_KEY = 'sds-theme';
|
|
|
15848
15853
|
*
|
|
15849
15854
|
* ```ts
|
|
15850
15855
|
* private readonly theme = inject(SdsThemeService);
|
|
15851
|
-
* this.theme.toggle(); // flip
|
|
15856
|
+
* this.theme.toggle(); // flip (to an explicit light/dark)
|
|
15857
|
+
* this.theme.setMode('system'); // follow the OS again
|
|
15852
15858
|
* this.theme.isDark(); // read (a signal)
|
|
15859
|
+
* this.theme.mode(); // 'system' | 'light' | 'dark'
|
|
15853
15860
|
* ```
|
|
15854
15861
|
*
|
|
15855
|
-
*
|
|
15856
|
-
*
|
|
15857
|
-
*
|
|
15858
|
-
* safe under SSR / prerender (it simply no-ops without a DOM).
|
|
15862
|
+
* Two layers: {@link mode} is the choice (persisted to `localStorage` under `sds-theme`), {@link theme} is
|
|
15863
|
+
* what that resolves to. With no stored choice the mode is `system`, which tracks the OS setting live —
|
|
15864
|
+
* a first-time visitor in dark at the OS level lands in dark, and follows the OS if it flips. Every
|
|
15865
|
+
* browser access is guarded, so the service is safe under SSR / prerender (it simply no-ops without a DOM).
|
|
15859
15866
|
*/
|
|
15860
15867
|
class SdsThemeService {
|
|
15861
15868
|
document = inject(DOCUMENT);
|
|
15862
|
-
|
|
15869
|
+
/** The person's choice. */
|
|
15870
|
+
mode = signal(this.initialMode(), ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
15871
|
+
/** The OS preference, kept live by a `matchMedia` listener. */
|
|
15872
|
+
systemDark = signal(this.queryDark()?.matches ?? false, ...(ngDevMode ? [{ debugName: "systemDark" }] : []));
|
|
15873
|
+
/** The theme painted: the explicit choice, or the OS one under `system`. */
|
|
15874
|
+
theme = computed(() => {
|
|
15875
|
+
const mode = this.mode();
|
|
15876
|
+
return mode === 'system' ? (this.systemDark() ? 'dark' : 'light') : mode;
|
|
15877
|
+
}, ...(ngDevMode ? [{ debugName: "theme" }] : []));
|
|
15863
15878
|
isDark = computed(() => this.theme() === 'dark', ...(ngDevMode ? [{ debugName: "isDark" }] : []));
|
|
15864
15879
|
constructor() {
|
|
15865
|
-
// Keep the DOM class and the stored
|
|
15866
|
-
//
|
|
15867
|
-
effect(() => this.apply(this.theme()));
|
|
15880
|
+
// Keep the DOM class and the stored choice in lockstep with the signals — one effect, so any caller
|
|
15881
|
+
// (toggle, setTheme, setMode, or the OS flipping under `system`) applies uniformly.
|
|
15882
|
+
effect(() => this.apply(this.theme(), this.mode()));
|
|
15883
|
+
const query = this.queryDark();
|
|
15884
|
+
if (query) {
|
|
15885
|
+
const onChange = (event) => this.systemDark.set(event.matches);
|
|
15886
|
+
query.addEventListener?.('change', onChange);
|
|
15887
|
+
inject(DestroyRef).onDestroy(() => query.removeEventListener?.('change', onChange));
|
|
15888
|
+
}
|
|
15868
15889
|
}
|
|
15869
|
-
/** Flip between light and dark. */
|
|
15890
|
+
/** Flip between light and dark (an explicit choice, leaving `system`). */
|
|
15870
15891
|
toggle() {
|
|
15871
|
-
this.
|
|
15892
|
+
this.mode.set(this.theme() === 'light' ? 'dark' : 'light');
|
|
15872
15893
|
}
|
|
15873
15894
|
/** Set an explicit theme. */
|
|
15874
15895
|
setTheme(theme) {
|
|
15875
|
-
this.
|
|
15896
|
+
this.mode.set(theme);
|
|
15897
|
+
}
|
|
15898
|
+
/** Set the choice, `system` included. */
|
|
15899
|
+
setMode(mode) {
|
|
15900
|
+
this.mode.set(mode);
|
|
15876
15901
|
}
|
|
15877
|
-
|
|
15902
|
+
initialMode() {
|
|
15878
15903
|
try {
|
|
15879
|
-
const stored = this.readStorage()?.getItem(
|
|
15880
|
-
if (stored
|
|
15904
|
+
const stored = this.readStorage()?.getItem(SDS_THEME_STORAGE_KEY);
|
|
15905
|
+
if (isSdsThemeMode(stored))
|
|
15881
15906
|
return stored;
|
|
15882
|
-
const win = this.document.defaultView;
|
|
15883
|
-
if (win?.matchMedia('(prefers-color-scheme: dark)').matches)
|
|
15884
|
-
return 'dark';
|
|
15885
15907
|
}
|
|
15886
15908
|
catch {
|
|
15887
|
-
/* no storage
|
|
15909
|
+
/* no storage (SSR, privacy mode) — fall through to following the OS */
|
|
15888
15910
|
}
|
|
15889
|
-
return '
|
|
15911
|
+
return 'system';
|
|
15890
15912
|
}
|
|
15891
|
-
|
|
15913
|
+
queryDark() {
|
|
15914
|
+
try {
|
|
15915
|
+
return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)') ?? null;
|
|
15916
|
+
}
|
|
15917
|
+
catch {
|
|
15918
|
+
return null;
|
|
15919
|
+
}
|
|
15920
|
+
}
|
|
15921
|
+
apply(theme, mode) {
|
|
15892
15922
|
const root = this.document.documentElement;
|
|
15893
15923
|
root.classList.toggle('dark', theme === 'dark');
|
|
15894
15924
|
// Let the UA paint form controls / scrollbars to match.
|
|
15895
15925
|
root.style.colorScheme = theme;
|
|
15896
15926
|
try {
|
|
15897
|
-
|
|
15927
|
+
// The CHOICE is stored, not the resolved theme — `system` must stay `system`, or the first visit
|
|
15928
|
+
// would freeze whatever the OS happened to be set to.
|
|
15929
|
+
this.readStorage()?.setItem(SDS_THEME_STORAGE_KEY, mode);
|
|
15898
15930
|
}
|
|
15899
15931
|
catch {
|
|
15900
15932
|
/* storage unavailable — the class is still applied; only persistence is skipped */
|
|
@@ -15984,6 +16016,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
15984
16016
|
}]
|
|
15985
16017
|
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], darkLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "darkLabel", required: false }] }], lightLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "lightLabel", required: false }] }] } });
|
|
15986
16018
|
|
|
16019
|
+
const SDS_UI_PREF_LANG_PARAM = 'lang';
|
|
16020
|
+
const SDS_UI_PREF_THEME_PARAM = 'theme';
|
|
16021
|
+
const ABSOLUTE = /^[a-z][a-z0-9+.-]*:/i;
|
|
16022
|
+
const PLACEHOLDER_ORIGIN = 'http://sds.invalid';
|
|
16023
|
+
/**
|
|
16024
|
+
* `url` with `lang` / `theme` set on its query (overwriting any present), the fragment kept. Accepts an
|
|
16025
|
+
* absolute URL or a root-relative path (returned root-relative). Invalid themes are dropped, not sent.
|
|
16026
|
+
*
|
|
16027
|
+
* ```ts
|
|
16028
|
+
* appendUiPrefs('https://auth.example/continue#token=abc', { lang: 'fr', theme: 'dark' })
|
|
16029
|
+
* // → 'https://auth.example/continue?lang=fr&theme=dark#token=abc'
|
|
16030
|
+
* ```
|
|
16031
|
+
*/
|
|
16032
|
+
function appendUiPrefs(url, prefs) {
|
|
16033
|
+
const absolute = ABSOLUTE.test(url);
|
|
16034
|
+
let parsed;
|
|
16035
|
+
try {
|
|
16036
|
+
parsed = new URL(url, PLACEHOLDER_ORIGIN);
|
|
16037
|
+
}
|
|
16038
|
+
catch {
|
|
16039
|
+
return url;
|
|
16040
|
+
}
|
|
16041
|
+
const lang = prefs.lang?.trim();
|
|
16042
|
+
if (lang) {
|
|
16043
|
+
parsed.searchParams.set(SDS_UI_PREF_LANG_PARAM, lang);
|
|
16044
|
+
}
|
|
16045
|
+
if (isSdsThemeMode(prefs.theme)) {
|
|
16046
|
+
parsed.searchParams.set(SDS_UI_PREF_THEME_PARAM, prefs.theme);
|
|
16047
|
+
}
|
|
16048
|
+
return absolute ? parsed.toString() : parsed.pathname + parsed.search + parsed.hash;
|
|
16049
|
+
}
|
|
16050
|
+
/**
|
|
16051
|
+
* The prefs carried by a query string (`location.search`), validated: `lang` only if it is one of
|
|
16052
|
+
* `supportedLangs`, `theme` only if it is a {@link SdsThemeMode}. Anything else reads as absent.
|
|
16053
|
+
*/
|
|
16054
|
+
function readUiPrefs(search, supportedLangs) {
|
|
16055
|
+
const params = new URLSearchParams(search);
|
|
16056
|
+
const lang = params.get(SDS_UI_PREF_LANG_PARAM);
|
|
16057
|
+
const theme = params.get(SDS_UI_PREF_THEME_PARAM);
|
|
16058
|
+
return {
|
|
16059
|
+
lang: lang && supportedLangs.includes(lang) ? lang : null,
|
|
16060
|
+
theme: isSdsThemeMode(theme) ? theme : null,
|
|
16061
|
+
};
|
|
16062
|
+
}
|
|
16063
|
+
/** `url` without the `lang` / `theme` params (everything else, fragment included, untouched). */
|
|
16064
|
+
function stripUiPrefs(url) {
|
|
16065
|
+
const absolute = ABSOLUTE.test(url);
|
|
16066
|
+
let parsed;
|
|
16067
|
+
try {
|
|
16068
|
+
parsed = new URL(url, PLACEHOLDER_ORIGIN);
|
|
16069
|
+
}
|
|
16070
|
+
catch {
|
|
16071
|
+
return url;
|
|
16072
|
+
}
|
|
16073
|
+
if (!parsed.searchParams.has(SDS_UI_PREF_LANG_PARAM) &&
|
|
16074
|
+
!parsed.searchParams.has(SDS_UI_PREF_THEME_PARAM)) {
|
|
16075
|
+
return url;
|
|
16076
|
+
}
|
|
16077
|
+
parsed.searchParams.delete(SDS_UI_PREF_LANG_PARAM);
|
|
16078
|
+
parsed.searchParams.delete(SDS_UI_PREF_THEME_PARAM);
|
|
16079
|
+
return absolute ? parsed.toString() : parsed.pathname + parsed.search + parsed.hash;
|
|
16080
|
+
}
|
|
16081
|
+
|
|
15987
16082
|
/**
|
|
15988
16083
|
* Shared collapse state for the sidebar and its nav items.
|
|
15989
16084
|
*
|
|
@@ -18313,6 +18408,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
18313
18408
|
`, styles: [".animate-sds-menu{animation:sds-menu-in .14s ease-out}@keyframes sds-menu-in{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){.animate-sds-menu{animation:none}}\n"] }]
|
|
18314
18409
|
}], propDecorators: { trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], languages: [{ type: i0.Input, args: [{ isSignal: true, alias: "languages", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }, { type: i0.Output, args: ["currentChange"] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], menuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuLabel", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], openChange: [{ type: i0.Output, args: ["openChange"] }] } });
|
|
18315
18410
|
|
|
18411
|
+
/**
|
|
18412
|
+
* Fixed, theme- AND brand-independent hues on purpose: a non-production marker must look identical in every
|
|
18413
|
+
* app, brand and colour-scheme, so it uses literal sky / amber rather than themeable design-system tokens
|
|
18414
|
+
* (which a brand preset could redefine). Sky for DEV, amber for TEST.
|
|
18415
|
+
*/
|
|
18416
|
+
const MARKERS = {
|
|
18417
|
+
dev: { label: 'DEV', bar: 'bg-[#38bdf8]', tab: 'bg-[#38bdf8] text-[#0c1a24]', variant: 'dev' },
|
|
18418
|
+
test: { label: 'TEST', bar: 'bg-[#f59e0b]', tab: 'bg-[#f59e0b] text-[#1c1916]', variant: 'test' },
|
|
18419
|
+
};
|
|
18420
|
+
/**
|
|
18421
|
+
* Non-production environment marker: a 3px rule pinned across the very top of the viewport with a small tab
|
|
18422
|
+
* hanging from its centre — sky **DEV** or amber **TEST**, nothing in production. Fixed and click-through,
|
|
18423
|
+
* above all app chrome, so a dev or test environment is never mistaken for the live one.
|
|
18424
|
+
*
|
|
18425
|
+
* Presentation only, no i18n or environment dependency: the host app supplies the resolved `[env]` (from its
|
|
18426
|
+
* `environment.env`, or — for an SSR app — from the request host) and, optionally, the translated
|
|
18427
|
+
* screen-reader sentences. Render it once from the app's root component.
|
|
18428
|
+
*/
|
|
18429
|
+
class SdsEnvBanner {
|
|
18430
|
+
/** The resolved build environment. Only `dev` and `test` show a marker; `prod`/anything else shows nothing. */
|
|
18431
|
+
env = input(...(ngDevMode ? [undefined, { debugName: "env" }] : []));
|
|
18432
|
+
/** Screen-reader sentence for the DEV marker (pass a translated string; English default). */
|
|
18433
|
+
devSrLabel = input('Development environment — not production', ...(ngDevMode ? [{ debugName: "devSrLabel" }] : []));
|
|
18434
|
+
/** Screen-reader sentence for the TEST marker (pass a translated string; English default). */
|
|
18435
|
+
testSrLabel = input('Test environment — not production', ...(ngDevMode ? [{ debugName: "testSrLabel" }] : []));
|
|
18436
|
+
marker = computed(() => {
|
|
18437
|
+
const env = this.env();
|
|
18438
|
+
return env === 'dev' ? MARKERS.dev : env === 'test' ? MARKERS.test : null;
|
|
18439
|
+
}, ...(ngDevMode ? [{ debugName: "marker" }] : []));
|
|
18440
|
+
srLabel = computed(() => {
|
|
18441
|
+
const m = this.marker();
|
|
18442
|
+
return m ? (m.variant === 'dev' ? this.devSrLabel() : this.testSrLabel()) : '';
|
|
18443
|
+
}, ...(ngDevMode ? [{ debugName: "srLabel" }] : []));
|
|
18444
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsEnvBanner, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18445
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdsEnvBanner, isStandalone: true, selector: "sds-env-banner", inputs: { env: { classPropertyName: "env", publicName: "env", isSignal: true, isRequired: false, transformFunction: null }, devSrLabel: { classPropertyName: "devSrLabel", publicName: "devSrLabel", isSignal: true, isRequired: false, transformFunction: null }, testSrLabel: { classPropertyName: "testSrLabel", publicName: "testSrLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
18446
|
+
@if (marker(); as m) {
|
|
18447
|
+
<div
|
|
18448
|
+
class="pointer-events-none fixed inset-x-0 top-0 z-[2147483000] h-[3px]"
|
|
18449
|
+
[class]="m.bar"
|
|
18450
|
+
role="note"
|
|
18451
|
+
data-testid="env-banner"
|
|
18452
|
+
>
|
|
18453
|
+
<span
|
|
18454
|
+
class="absolute left-1/2 top-0 -translate-x-1/2 rounded-b-lg px-3 pb-[3px] pt-px font-sans text-[11px] font-extrabold leading-4 tracking-[0.12em] shadow-[0_2px_6px_rgb(0_0_0/0.18)]"
|
|
18455
|
+
[class]="m.tab"
|
|
18456
|
+
aria-hidden="true"
|
|
18457
|
+
>{{ m.label }}</span
|
|
18458
|
+
>
|
|
18459
|
+
@if (srLabel(); as sr) {
|
|
18460
|
+
<span class="sr-only">{{ sr }}</span>
|
|
18461
|
+
}
|
|
18462
|
+
</div>
|
|
18463
|
+
}
|
|
18464
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18465
|
+
}
|
|
18466
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsEnvBanner, decorators: [{
|
|
18467
|
+
type: Component,
|
|
18468
|
+
args: [{
|
|
18469
|
+
selector: 'sds-env-banner',
|
|
18470
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
18471
|
+
template: `
|
|
18472
|
+
@if (marker(); as m) {
|
|
18473
|
+
<div
|
|
18474
|
+
class="pointer-events-none fixed inset-x-0 top-0 z-[2147483000] h-[3px]"
|
|
18475
|
+
[class]="m.bar"
|
|
18476
|
+
role="note"
|
|
18477
|
+
data-testid="env-banner"
|
|
18478
|
+
>
|
|
18479
|
+
<span
|
|
18480
|
+
class="absolute left-1/2 top-0 -translate-x-1/2 rounded-b-lg px-3 pb-[3px] pt-px font-sans text-[11px] font-extrabold leading-4 tracking-[0.12em] shadow-[0_2px_6px_rgb(0_0_0/0.18)]"
|
|
18481
|
+
[class]="m.tab"
|
|
18482
|
+
aria-hidden="true"
|
|
18483
|
+
>{{ m.label }}</span
|
|
18484
|
+
>
|
|
18485
|
+
@if (srLabel(); as sr) {
|
|
18486
|
+
<span class="sr-only">{{ sr }}</span>
|
|
18487
|
+
}
|
|
18488
|
+
</div>
|
|
18489
|
+
}
|
|
18490
|
+
`,
|
|
18491
|
+
}]
|
|
18492
|
+
}], propDecorators: { env: [{ type: i0.Input, args: [{ isSignal: true, alias: "env", required: false }] }], devSrLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "devSrLabel", required: false }] }], testSrLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "testSrLabel", required: false }] }] } });
|
|
18493
|
+
|
|
18316
18494
|
/*
|
|
18317
18495
|
* Public API Surface of saitech-design-system — the Saitech / App design system.
|
|
18318
18496
|
*/
|
|
@@ -18322,5 +18500,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
18322
18500
|
* Generated bundle index. Do not edit.
|
|
18323
18501
|
*/
|
|
18324
18502
|
|
|
18325
|
-
export { SDS_ALLERGENS, SDS_ALLERGEN_ICONS, SDS_ALLERGEN_LABELS_EN, SDS_ICONS, SDS_PHONE_COUNTRIES, SdsAccordion, SdsAccordionContent, SdsAccordionHeader, SdsAccordionPanel, SdsAccordionStore, SdsAddressAutocomplete, SdsAddressExtra, SdsAllergenIcon, SdsAvatar, SdsBadge, SdsBulkBar, SdsButton, SdsCalendar, SdsCard, SdsCheckbox, SdsChecklistRow, SdsChip, SdsChipGroup, SdsDatePicker, SdsFileDrop, SdsIcon, SdsImageCropper, SdsInput, SdsInputNumber, SdsLanguageSwitcher, SdsLocalizedInput, SdsMenu, SdsMenuItem, SdsMenuTrigger, SdsMultiSelect, SdsNavGroup, SdsNavItem, SdsOtpInput, SdsPaginator, SdsPhoneInput, SdsRadio, SdsScore, SdsSearchCommand, SdsSegmented, SdsSelect, SdsSelectEmpty, SdsSelectFooter, SdsSelectOption, SdsShell, SdsSidebar, SdsSortableHandle, SdsSortableItem, SdsSortableList, SdsStatusTile, SdsTab, SdsTabList, SdsTabPanel, SdsTabPanels, SdsTable, SdsTableCell, SdsTableEmpty, SdsTableHeader, SdsTableRowExpansion, SdsTabs, SdsTabsStore, SdsTextarea, SdsThemeService, SdsThemeToggle, SdsTimeInput, SdsToastHost, SdsToastService, SdsToggleSwitch, SdsTopbar, SdsTriStateChip, SdsUserMenu, SidebarStore, addDays, addMonths, addMonthsKeepDay, formatDdMmYyyy, formatHhMm, isOutOfRange, isSameDay, isoDay, pad2, sdsFileMatchesAccept, sdsFormatBytes, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth };
|
|
18503
|
+
export { SDS_ALLERGENS, SDS_ALLERGEN_ICONS, SDS_ALLERGEN_LABELS_EN, SDS_ICONS, SDS_PHONE_COUNTRIES, SDS_THEME_STORAGE_KEY, SDS_UI_PREF_LANG_PARAM, SDS_UI_PREF_THEME_PARAM, SdsAccordion, SdsAccordionContent, SdsAccordionHeader, SdsAccordionPanel, SdsAccordionStore, SdsAddressAutocomplete, SdsAddressExtra, SdsAllergenIcon, SdsAvatar, SdsBadge, SdsBulkBar, SdsButton, SdsCalendar, SdsCard, SdsCheckbox, SdsChecklistRow, SdsChip, SdsChipGroup, SdsDatePicker, SdsEnvBanner, SdsFileDrop, SdsIcon, SdsImageCropper, SdsInput, SdsInputNumber, SdsLanguageSwitcher, SdsLocalizedInput, SdsMenu, SdsMenuItem, SdsMenuTrigger, SdsMultiSelect, SdsNavGroup, SdsNavItem, SdsOtpInput, SdsPaginator, SdsPhoneInput, SdsRadio, SdsScore, SdsSearchCommand, SdsSegmented, SdsSelect, SdsSelectEmpty, SdsSelectFooter, SdsSelectOption, SdsShell, SdsSidebar, SdsSortableHandle, SdsSortableItem, SdsSortableList, SdsStatusTile, SdsTab, SdsTabList, SdsTabPanel, SdsTabPanels, SdsTable, SdsTableCell, SdsTableEmpty, SdsTableHeader, SdsTableRowExpansion, SdsTabs, SdsTabsStore, SdsTextarea, SdsThemeService, SdsThemeToggle, SdsTimeInput, SdsToastHost, SdsToastService, SdsToggleSwitch, SdsTopbar, SdsTriStateChip, SdsUserMenu, SidebarStore, addDays, addMonths, addMonthsKeepDay, appendUiPrefs, formatDdMmYyyy, formatHhMm, isOutOfRange, isSameDay, isSdsThemeMode, isoDay, pad2, readUiPrefs, sdsFileMatchesAccept, sdsFormatBytes, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth, stripUiPrefs };
|
|
18326
18504
|
//# sourceMappingURL=besaitech-ng-design-system.mjs.map
|