lupine.components 1.1.59 → 1.1.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/package.json +1 -1
- package/src/components/slide-page-component-demo.tsx +1 -1
- package/src/demo/demo-container.tsx +1 -1
- package/src/frames/slider-frame.tsx +3 -3
- package/src/lib/index.ts +1 -0
- package/src/lib/local-storage-wrapper.ts +47 -0
- package/src/styles/compute-theme-vars.ts +103 -0
- package/src/styles/index.ts +4 -3
package/package.json
CHANGED
|
@@ -322,7 +322,7 @@ export const slidePageDemo: DemoStory<SlidePageProps> = {
|
|
|
322
322
|
style={{
|
|
323
323
|
padding: '12px 16px',
|
|
324
324
|
borderRadius: '8px',
|
|
325
|
-
background: 'var(--bg-
|
|
325
|
+
background: 'var(--secondary-bg-color, #f2f2f7)',
|
|
326
326
|
fontSize: '13px',
|
|
327
327
|
color: 'var(--text-secondary, #64748b)',
|
|
328
328
|
lineHeight: '1.5',
|
|
@@ -28,7 +28,7 @@ export const DemoContainer = (props: DemoContainerProps) => {
|
|
|
28
28
|
minHeight: '50px',
|
|
29
29
|
maxHeight: '40%',
|
|
30
30
|
overflowY: 'auto',
|
|
31
|
-
borderTop: '1px solid var(--border-color, #ccc)',
|
|
31
|
+
borderTop: '1px solid var(--secondary-border-color, #ccc)',
|
|
32
32
|
padding: 'var(--space-m, 8px)',
|
|
33
33
|
},
|
|
34
34
|
};
|
|
@@ -16,7 +16,7 @@ import { MediaQueryMaxWidth, VNode, stopPropagation } from 'lupine.components';
|
|
|
16
16
|
import { SliderHelper, SliderHelperCloseProps } from './slider-helper';
|
|
17
17
|
|
|
18
18
|
export type SliderFrameHookProps = {
|
|
19
|
-
load?: (children: VNode<any
|
|
19
|
+
load?: (children: VNode<any>, addBottomSafearea?: boolean) => void;
|
|
20
20
|
close?: (event: Event) => void;
|
|
21
21
|
isOpened?: () => boolean;
|
|
22
22
|
};
|
|
@@ -34,13 +34,13 @@ export const SliderFrame = (props: SliderFrameProps) => {
|
|
|
34
34
|
let opened = false;
|
|
35
35
|
|
|
36
36
|
if (props.hook) {
|
|
37
|
-
props.hook.load = (children) => {
|
|
37
|
+
props.hook.load = (children, addBottomSafearea) => {
|
|
38
38
|
opened = true;
|
|
39
39
|
SliderHelper.show({
|
|
40
40
|
direction: props.direction || 'right',
|
|
41
41
|
children,
|
|
42
42
|
maxWidth: props.maxWidth,
|
|
43
|
-
addBottomSafearea: props.addBottomSafearea ?? false,
|
|
43
|
+
addBottomSafearea: typeof addBottomSafearea === 'boolean' ? addBottomSafearea : (props.addBottomSafearea ?? false),
|
|
44
44
|
closeEvent: () => {
|
|
45
45
|
opened = false;
|
|
46
46
|
closeSlider = undefined;
|
package/src/lib/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './dynamical-load';
|
|
|
18
18
|
export * from './find-parent-tag';
|
|
19
19
|
export * from './format-bytes';
|
|
20
20
|
export * from './lite-dom';
|
|
21
|
+
export * from './local-storage-wrapper'
|
|
21
22
|
export * from './message-hub';
|
|
22
23
|
export * from './observable';
|
|
23
24
|
export * from './path-utils';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class LocalStorageWrapper {
|
|
2
|
+
private prefix: string;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates an instance of LocStorage.
|
|
6
|
+
* @param prefix - The prefix applied to all storage keys.
|
|
7
|
+
*/
|
|
8
|
+
constructor(prefix: string) {
|
|
9
|
+
this.prefix = prefix;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
set(key: string, value: string | null) {
|
|
13
|
+
if (typeof window === 'undefined') return;
|
|
14
|
+
if (value === null) {
|
|
15
|
+
window.localStorage.removeItem(this.makeKey(key));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
window.localStorage.setItem(this.makeKey(key), value);
|
|
19
|
+
}
|
|
20
|
+
get(key: string): string | null {
|
|
21
|
+
if (typeof window === 'undefined') return null;
|
|
22
|
+
return window.localStorage.getItem(this.makeKey(key));
|
|
23
|
+
}
|
|
24
|
+
setJson(key: string, value: object | null) {
|
|
25
|
+
if (typeof window === 'undefined') return;
|
|
26
|
+
if (value === null) {
|
|
27
|
+
window.localStorage.removeItem(this.makeKey(key));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
window.localStorage.setItem(this.makeKey(key), JSON.stringify(value));
|
|
31
|
+
}
|
|
32
|
+
getJson(key: string): object | null {
|
|
33
|
+
if (typeof window === 'undefined') return null;
|
|
34
|
+
const val = window.localStorage.getItem(this.makeKey(key));
|
|
35
|
+
try {
|
|
36
|
+
if (!val) return null;
|
|
37
|
+
return JSON.parse(val);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(`[LocalStorage Error] Failed to get key "${key}":`, error);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private makeKey(key: string): string {
|
|
45
|
+
return `${this.prefix}${key}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { blendColor } from "lupine.web";
|
|
2
|
+
|
|
3
|
+
export interface ComputedThemeVars {
|
|
4
|
+
'--primary-color': string;
|
|
5
|
+
'--primary-bg-color': string;
|
|
6
|
+
'--primary-border-color': string;
|
|
7
|
+
'--primary-border': string;
|
|
8
|
+
'--primary-color-disabled': string;
|
|
9
|
+
'--primary-disabled-opacity': string;
|
|
10
|
+
'--secondary-color': string;
|
|
11
|
+
'--secondary-bg-color': string;
|
|
12
|
+
'--secondary-border-color': string;
|
|
13
|
+
'--secondary-border': string;
|
|
14
|
+
'--activatable-color-normal': string;
|
|
15
|
+
'--activatable-bg-color-normal': string;
|
|
16
|
+
'--activatable-color-hover': string;
|
|
17
|
+
'--activatable-bg-color-hover': string;
|
|
18
|
+
'--activatable-color-selected': string;
|
|
19
|
+
'--activatable-bg-color-selected': string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Computes a full set of global theme CSS variables from the theme mode,
|
|
24
|
+
* primary background color, and primary text color.
|
|
25
|
+
*
|
|
26
|
+
* Design Specifications:
|
|
27
|
+
* - `--secondary-color` (Secondary / Muted Text):
|
|
28
|
+
* - Dark mode: blendColor(primaryText, primaryBg, 0.38) (~62% text + 38% bg)
|
|
29
|
+
* - Light mode: blendColor(primaryText, primaryBg, 0.42) (~58% text + 42% bg)
|
|
30
|
+
* - Ensures soft readability while strictly meeting WCAG AA contrast standards (>= 4.5:1).
|
|
31
|
+
* - `--secondary-bg-color` (Surface / Card / Modal Background):
|
|
32
|
+
* - Dark mode: blendColor(primaryBg, '#FFFFFF', 0.10) (elevated by +10% lightness)
|
|
33
|
+
* - Light mode: blendColor(primaryBg, '#FFFFFF', 0.55) (elevated towards white by +55%)
|
|
34
|
+
* - `--primary-border-color` & `--secondary-border-color`:
|
|
35
|
+
* - Balanced contrast border tints for cards, buttons, and dividers.
|
|
36
|
+
* - `--activatable-...`:
|
|
37
|
+
* - Normal, hover, and selected states for buttons, tabs, pills, and menus.
|
|
38
|
+
*/
|
|
39
|
+
export function computeThemeVars(mode: 'light' | 'dark', primaryBg: string, primaryText: string): ComputedThemeVars {
|
|
40
|
+
const isDark = mode === 'dark';
|
|
41
|
+
|
|
42
|
+
// 1. Secondary Text
|
|
43
|
+
const secondaryColor = isDark
|
|
44
|
+
? blendColor(primaryText, primaryBg, 0.38)
|
|
45
|
+
: blendColor(primaryText, primaryBg, 0.42);
|
|
46
|
+
|
|
47
|
+
// 2. Card / Surface Elevation Background
|
|
48
|
+
const secondaryBg = isDark
|
|
49
|
+
? blendColor(primaryBg, '#FFFFFF', 0.10)
|
|
50
|
+
: blendColor(primaryBg, '#FFFFFF', 0.55);
|
|
51
|
+
|
|
52
|
+
// 3. Borders & Dividers
|
|
53
|
+
const primaryBorderColor = isDark
|
|
54
|
+
? blendColor(primaryBg, primaryText, 0.35)
|
|
55
|
+
: blendColor(primaryBg, primaryText, 0.25);
|
|
56
|
+
|
|
57
|
+
const secondaryBorderColor = isDark
|
|
58
|
+
? blendColor(primaryBg, primaryText, 0.18)
|
|
59
|
+
: blendColor(primaryBg, primaryText, 0.12);
|
|
60
|
+
|
|
61
|
+
// 4. Disabled Text
|
|
62
|
+
const primaryColorDisabled = isDark
|
|
63
|
+
? blendColor(primaryText, primaryBg, 0.60)
|
|
64
|
+
: blendColor(primaryText, primaryBg, 0.65);
|
|
65
|
+
|
|
66
|
+
// 5. Activatable Hover State
|
|
67
|
+
const activatableBgHover = isDark
|
|
68
|
+
? blendColor(primaryBg, '#FFFFFF', 0.16)
|
|
69
|
+
: blendColor(primaryBg, primaryText, 0.08);
|
|
70
|
+
|
|
71
|
+
const activatableColorHover = isDark ? '#FFFFFF' : primaryText;
|
|
72
|
+
|
|
73
|
+
// 6. Activatable Selected State
|
|
74
|
+
const activatableBgSelected = isDark
|
|
75
|
+
? blendColor(primaryBg, '#FFFFFF', 0.22)
|
|
76
|
+
: blendColor(primaryBg, primaryText, 0.14);
|
|
77
|
+
|
|
78
|
+
const activatableColorSelected = isDark ? '#FFFFFF' : primaryText;
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
// Primary Group
|
|
82
|
+
'--primary-color': primaryText,
|
|
83
|
+
'--primary-bg-color': primaryBg,
|
|
84
|
+
'--primary-border-color': primaryBorderColor,
|
|
85
|
+
'--primary-border': `1px solid ${primaryBorderColor}`,
|
|
86
|
+
'--primary-color-disabled': primaryColorDisabled,
|
|
87
|
+
'--primary-disabled-opacity': isDark ? '0.6' : '0.45',
|
|
88
|
+
|
|
89
|
+
// Secondary Group
|
|
90
|
+
'--secondary-color': secondaryColor,
|
|
91
|
+
'--secondary-bg-color': secondaryBg,
|
|
92
|
+
'--secondary-border-color': secondaryBorderColor,
|
|
93
|
+
'--secondary-border': `1px solid ${secondaryBorderColor}`,
|
|
94
|
+
|
|
95
|
+
// Activatable Group (Buttons, Pills, Tabs, Menus)
|
|
96
|
+
'--activatable-color-normal': primaryText,
|
|
97
|
+
'--activatable-bg-color-normal': secondaryBg,
|
|
98
|
+
'--activatable-color-hover': activatableColorHover,
|
|
99
|
+
'--activatable-bg-color-hover': activatableBgHover,
|
|
100
|
+
'--activatable-color-selected': activatableColorSelected,
|
|
101
|
+
'--activatable-bg-color-selected': activatableBgSelected,
|
|
102
|
+
};
|
|
103
|
+
}
|
package/src/styles/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
1
|
+
export * from './base-themes';
|
|
2
|
+
export * from './compute-theme-vars';
|
|
3
3
|
export * from './dark-themes';
|
|
4
4
|
export * from './light-themes';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './media-query';
|
|
6
|
+
export * from './shared-themes';
|