@zhang_jifan/fanui 2.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.
Files changed (127) hide show
  1. package/ACCESSIBILITY.md +61 -0
  2. package/CHANGELOG.md +112 -0
  3. package/COMMERCIAL-LICENSE.md +71 -0
  4. package/DESIGN-SYSTEM.md +294 -0
  5. package/LICENSE +661 -0
  6. package/README.md +348 -0
  7. package/USAGE.md +1926 -0
  8. package/_index.scss +20 -0
  9. package/dist/fanui.cjs +15 -0
  10. package/dist/fanui.css +28209 -0
  11. package/dist/fanui.d.ts +353 -0
  12. package/dist/fanui.esm.js +71 -0
  13. package/dist/fanui.js +4782 -0
  14. package/dist/fanui.min.css +1 -0
  15. package/dist/fanui.mjs +71 -0
  16. package/dist/modules/fanui-advanced.css +830 -0
  17. package/dist/modules/fanui-advanced.min.css +129 -0
  18. package/dist/modules/fanui-alert.css +575 -0
  19. package/dist/modules/fanui-alert.min.css +122 -0
  20. package/dist/modules/fanui-badge.css +426 -0
  21. package/dist/modules/fanui-badge.min.css +77 -0
  22. package/dist/modules/fanui-base.css +1394 -0
  23. package/dist/modules/fanui-base.min.css +236 -0
  24. package/dist/modules/fanui-blog.css +762 -0
  25. package/dist/modules/fanui-blog.min.css +108 -0
  26. package/dist/modules/fanui-button.css +526 -0
  27. package/dist/modules/fanui-button.min.css +56 -0
  28. package/dist/modules/fanui-card.css +291 -0
  29. package/dist/modules/fanui-card.min.css +52 -0
  30. package/dist/modules/fanui-choice.css +539 -0
  31. package/dist/modules/fanui-choice.min.css +83 -0
  32. package/dist/modules/fanui-dashboard.css +1057 -0
  33. package/dist/modules/fanui-dashboard.min.css +160 -0
  34. package/dist/modules/fanui-data.css +687 -0
  35. package/dist/modules/fanui-data.min.css +125 -0
  36. package/dist/modules/fanui-feedback.css +432 -0
  37. package/dist/modules/fanui-feedback.min.css +79 -0
  38. package/dist/modules/fanui-form.css +779 -0
  39. package/dist/modules/fanui-form.min.css +123 -0
  40. package/dist/modules/fanui-glass.css +497 -0
  41. package/dist/modules/fanui-glass.min.css +46 -0
  42. package/dist/modules/fanui-input-plus.css +799 -0
  43. package/dist/modules/fanui-input-plus.min.css +124 -0
  44. package/dist/modules/fanui-interactive.css +960 -0
  45. package/dist/modules/fanui-interactive.min.css +138 -0
  46. package/dist/modules/fanui-layout.css +4399 -0
  47. package/dist/modules/fanui-layout.min.css +1172 -0
  48. package/dist/modules/fanui-marketing.css +1125 -0
  49. package/dist/modules/fanui-marketing.min.css +144 -0
  50. package/dist/modules/fanui-nav.css +458 -0
  51. package/dist/modules/fanui-nav.min.css +76 -0
  52. package/dist/modules/fanui-overlay.css +547 -0
  53. package/dist/modules/fanui-overlay.min.css +91 -0
  54. package/dist/modules/fanui-table.css +290 -0
  55. package/dist/modules/fanui-table.min.css +62 -0
  56. package/dist/modules/fanui-tabs.css +333 -0
  57. package/dist/modules/fanui-tabs.min.css +58 -0
  58. package/dist/modules/fanui-themes.css +2728 -0
  59. package/dist/modules/fanui-themes.min.css +40 -0
  60. package/dist/modules/fanui-tokens.css +587 -0
  61. package/dist/modules/fanui-tokens.min.css +3 -0
  62. package/dist/modules/fanui-utilities.css +6557 -0
  63. package/dist/modules/fanui-utilities.min.css +1762 -0
  64. package/dist/modules/sizes.json +103 -0
  65. package/docs/MIGRATION-v2.md +179 -0
  66. package/examples/01-script-tag.html +149 -0
  67. package/examples/02-react/README.md +39 -0
  68. package/examples/02-react/index.html +12 -0
  69. package/examples/02-react/package.json +20 -0
  70. package/examples/02-react/src/App.jsx +108 -0
  71. package/examples/02-react/src/main.jsx +13 -0
  72. package/examples/02-react/src/useFanUI.js +87 -0
  73. package/examples/02-react/vite.config.js +6 -0
  74. package/examples/03-vue3/README.md +67 -0
  75. package/examples/03-vue3/index.html +12 -0
  76. package/examples/03-vue3/package.json +19 -0
  77. package/examples/03-vue3/src/App.vue +93 -0
  78. package/examples/03-vue3/src/main.js +8 -0
  79. package/examples/03-vue3/src/useFanUI.js +85 -0
  80. package/examples/03-vue3/vite.config.js +6 -0
  81. package/examples/04-vue2-cdn.html +93 -0
  82. package/examples/README.md +34 -0
  83. package/package.json +127 -0
  84. package/src/_functions.scss +319 -0
  85. package/src/_mixins.scss +1202 -0
  86. package/src/_tokens.scss +180 -0
  87. package/src/_variables.scss +491 -0
  88. package/src/base/_animations.scss +210 -0
  89. package/src/base/_reset.scss +359 -0
  90. package/src/base/_rtl.scss +133 -0
  91. package/src/base/_typography.scss +353 -0
  92. package/src/components/_advanced.scss +763 -0
  93. package/src/components/_alert.scss +322 -0
  94. package/src/components/_badge.scss +279 -0
  95. package/src/components/_blog.scss +693 -0
  96. package/src/components/_button.scss +351 -0
  97. package/src/components/_capabilities.scss +463 -0
  98. package/src/components/_card.scss +281 -0
  99. package/src/components/_choice.scss +444 -0
  100. package/src/components/_dashboard.scss +950 -0
  101. package/src/components/_data.scss +618 -0
  102. package/src/components/_feedback.scss +403 -0
  103. package/src/components/_form.scss +408 -0
  104. package/src/components/_glass.scss +374 -0
  105. package/src/components/_input-plus.scss +730 -0
  106. package/src/components/_interactive.scss +885 -0
  107. package/src/components/_marketing.scss +982 -0
  108. package/src/components/_nav.scss +480 -0
  109. package/src/components/_overlay.scss +517 -0
  110. package/src/components/_table.scss +276 -0
  111. package/src/components/_tabs.scss +338 -0
  112. package/src/fanui.d.ts +353 -0
  113. package/src/fanui.js +4782 -0
  114. package/src/fanui.scss +79 -0
  115. package/src/glass/_switches.scss +36 -0
  116. package/src/glass/_tokens.scss +259 -0
  117. package/src/layout/_container.scss +111 -0
  118. package/src/layout/_flex.scss +164 -0
  119. package/src/layout/_grid.scss +180 -0
  120. package/src/themes/_accents.scss +201 -0
  121. package/src/themes/_palettes.scss +180 -0
  122. package/src/utilities/_borders.scss +104 -0
  123. package/src/utilities/_display.scss +145 -0
  124. package/src/utilities/_effects.scss +210 -0
  125. package/src/utilities/_sizing.scss +123 -0
  126. package/src/utilities/_spacing.scss +118 -0
  127. package/src/utilities/_texture.scss +323 -0
@@ -0,0 +1,319 @@
1
+ // =============================================================================
2
+ // fanUI · 工具函数层 (Functions)
3
+ // -----------------------------------------------------------------------------
4
+ // 所有函数统一以 `fanui-` 为前缀,纯函数、无副作用、不产生任何 CSS 输出。
5
+ // 依赖:dart-sass >= 1.79(使用 color.channel 现代色彩 API,无弃用告警)
6
+ // =============================================================================
7
+
8
+ @use "sass:math";
9
+ @use "sass:color";
10
+ @use "sass:map";
11
+ @use "sass:list";
12
+ @use "sass:string";
13
+ @use "sass:meta";
14
+
15
+ // -----------------------------------------------------------------------------
16
+ // 1. 数值处理
17
+ // -----------------------------------------------------------------------------
18
+
19
+ /// 去除数值单位。
20
+ /// @example fanui-strip-unit(16px) => 16
21
+ @function fanui-strip-unit($number) {
22
+ @if not math.is-unitless($number) {
23
+ @return math.div($number, $number * 0 + 1);
24
+ }
25
+ @return $number;
26
+ }
27
+
28
+ /// px 转 rem。
29
+ /// @example fanui-px2rem(24px) => 1.5rem
30
+ @function fanui-px2rem($px, $base: 16px) {
31
+ $base: fanui-strip-unit($base);
32
+ @if $base == 0 {
33
+ @error "fanUI: fanui-px2rem() 的 $base 不能为 0。";
34
+ }
35
+ @return math.div(fanui-strip-unit($px), $base) * 1rem;
36
+ }
37
+
38
+ /// rem 转 px。
39
+ /// @example fanui-rem2px(1.5rem) => 24px
40
+ @function fanui-rem2px($rem, $base: 16px) {
41
+ $base: fanui-strip-unit($base);
42
+ @return math.div(fanui-strip-unit($rem) * $base, 1) * 1px;
43
+ }
44
+
45
+ /// px 转 em(相对父级字号)。
46
+ /// @example fanui-px2em(14px, 16px) => 0.875em
47
+ @function fanui-px2em($px, $context: 16px) {
48
+ $context: fanui-strip-unit($context);
49
+ @if $context == 0 {
50
+ @error "fanUI: fanui-px2em() 的 $context 不能为 0。";
51
+ }
52
+ @return math.div(fanui-strip-unit($px), $context) * 1em;
53
+ }
54
+
55
+ /// 取负值(0 保持为 0,避免出现 `-0`)。
56
+ @function fanui-negate($value) {
57
+ @if $value == 0 {
58
+ @return 0;
59
+ } @else {
60
+ @return -$value;
61
+ }
62
+ }
63
+
64
+ /// 百分比计算,返回 `%`。
65
+ /// @example fanui-percentage(6, 12) => 50%
66
+ @function fanui-percentage($value, $total) {
67
+ @if $total == 0 {
68
+ @error "fanUI: fanui-percentage() 的 $total 不能为 0。";
69
+ }
70
+ @return math.div(fanui-strip-unit($value), fanui-strip-unit($total)) * 100%;
71
+ }
72
+
73
+ /// 保留小数位。
74
+ @function fanui-round($number, $digits: 2) {
75
+ $factor: math.pow(10, $digits);
76
+ @return math.div(math.round($number * $factor), $factor);
77
+ }
78
+
79
+ // -----------------------------------------------------------------------------
80
+ // 2. 色彩处理
81
+ // -----------------------------------------------------------------------------
82
+
83
+ /// 设置颜色的透明度(现代 API,替代 rgba())。
84
+ /// @example fanui-alpha(#2563eb, 0.5) => rgba(37, 99, 235, 0.5)
85
+ @function fanui-alpha($color, $alpha) {
86
+ @return color.change($color, $alpha: $alpha);
87
+ }
88
+
89
+ /// 变亮:与白色混合。
90
+ /// @example fanui-tint(#2563eb, 20%) => 更浅的蓝
91
+ @function fanui-tint($color, $weight: 20%) {
92
+ @return color.mix(#ffffff, $color, $weight);
93
+ }
94
+
95
+ /// 变暗:与黑色混合。
96
+ @function fanui-shade($color, $weight: 20%) {
97
+ @return color.mix(#000000, $color, $weight);
98
+ }
99
+
100
+ /// 相对感知亮度(0~1),用于自动对比色计算。
101
+ @function fanui-luminance($color) {
102
+ @if meta.type-of($color) != "color" {
103
+ @error "fanUI: fanui-luminance() 需要颜色值,收到 `#{$color}`。";
104
+ }
105
+
106
+ $r: math.div(color.channel($color, "red", $space: rgb), 255);
107
+ $g: math.div(color.channel($color, "green", $space: rgb), 255);
108
+ $b: math.div(color.channel($color, "blue", $space: rgb), 255);
109
+
110
+ @if $r <= 0.03928 {
111
+ $r: math.div($r, 12.92);
112
+ } @else {
113
+ $r: math.pow(math.div($r + 0.055, 1.055), 2.4);
114
+ }
115
+
116
+ @if $g <= 0.03928 {
117
+ $g: math.div($g, 12.92);
118
+ } @else {
119
+ $g: math.pow(math.div($g + 0.055, 1.055), 2.4);
120
+ }
121
+
122
+ @if $b <= 0.03928 {
123
+ $b: math.div($b, 12.92);
124
+ } @else {
125
+ $b: math.pow(math.div($b + 0.055, 1.055), 2.4);
126
+ }
127
+
128
+ @return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
129
+ }
130
+
131
+ /// 依据背景色自动返回可读的前景色(深色或浅色)。
132
+ /// @example fanui-contrast(#000) => #ffffff
133
+ @function fanui-contrast($background, $light: #ffffff, $dark: #0f172a, $threshold: 0.4) {
134
+ @if fanui-luminance($background) > $threshold {
135
+ @return $dark;
136
+ }
137
+ @return $light;
138
+ }
139
+
140
+ /// 依据背景色返回「弱化前景色」(次级文本)。
141
+ @function fanui-contrast-muted($background, $light: rgba(#ffffff, 0.72), $dark: rgba(#0f172a, 0.66), $threshold: 0.4) {
142
+ @if fanui-luminance($background) > $threshold {
143
+ @return $dark;
144
+ }
145
+ @return $light;
146
+ }
147
+
148
+ /// 两色之间的插值(t: 0~1)。
149
+ @function fanui-mix($from, $to, $t: 0.5) {
150
+ @return color.mix($to, $from, fanui-round($t * 100, 2) * 1%);
151
+ }
152
+
153
+ /// 是否判定为「深色」。阈值 0.179 是 WCAG 里黑/白前景对比度相等点。
154
+ @function fanui-is-dark($color, $threshold: 0.179) {
155
+ @return fanui-luminance($color) < $threshold;
156
+ }
157
+
158
+ /// WCAG 2.1 对比度(1 ~ 21)。
159
+ /// @example fanui-contrast-ratio(#fff, #000) => 21
160
+ @function fanui-contrast-ratio($a, $b) {
161
+ $la: fanui-luminance($a);
162
+ $lb: fanui-luminance($b);
163
+ @if $la < $lb {
164
+ $tmp: $la;
165
+ $la: $lb;
166
+ $lb: $tmp;
167
+ }
168
+ @return math.div($la + 0.05, $lb + 0.05);
169
+ }
170
+
171
+ /// 在浅色 / 深色墨色中择优,返回对比度更高的前景色(保证最大可读性)。
172
+ /// 这是「自动可获得性」的核心:任何品牌色都能得到合规前景色。
173
+ /// @example fanui-best-fg(#06b6d4) => #0b1220
174
+ @function fanui-best-fg($bg, $light: #ffffff, $dark: #0b1220) {
175
+ @if fanui-contrast-ratio($bg, $light) >= fanui-contrast-ratio($bg, $dark) {
176
+ @return $light;
177
+ }
178
+ @return $dark;
179
+ }
180
+
181
+ /// 只有当「白色前景」达到 $min-ratio 时才返回 $light,否则返回 $dark。
182
+ /// 用于需要固定「白字」语义的实心按钮等场景。
183
+ @function fanui-white-fg-or($bg, $min-ratio: 4.5, $light: #ffffff, $dark: #0b1220) {
184
+ @if fanui-contrast-ratio($bg, $light) >= $min-ratio {
185
+ @return $light;
186
+ }
187
+ @return $dark;
188
+ }
189
+
190
+ /// 在候选色阶中择优:返回第一个满足对比度要求的色阶键。
191
+ /// 用于「主题色自动挑选合规主色阶」——浅色模式偏爱深阶、深色模式偏爱浅阶。
192
+ /// @example fanui-pick-tone((500: #06b6d4, 600: #0891b2, 700: #0e7490), (600, 700))
193
+ @function fanui-pick-tone($tones, $candidates, $min-ratio: 4.5, $against: #ffffff, $fallback: null) {
194
+ @each $name in $candidates {
195
+ @if map.has-key($tones, $name) {
196
+ $color: map.get($tones, $name);
197
+ @if fanui-contrast-ratio($color, $against) >= $min-ratio {
198
+ @return $name;
199
+ }
200
+ }
201
+ }
202
+ @if $fallback != null {
203
+ @return $fallback;
204
+ }
205
+ @return list.nth($candidates, 1);
206
+ }
207
+
208
+ /// 色相旋转(HSL 空间),用于派生辅助色 / 装饰色。
209
+ /// @example fanui-hue-shift(#0891b2, 40deg)
210
+ @function fanui-hue-shift($color, $deg) {
211
+ @return color.adjust($color, $hue: $deg, $space: hsl);
212
+ }
213
+
214
+ /// 饱和度调整(HSL 空间)。
215
+ @function fanui-saturate-color($color, $amount) {
216
+ @return color.adjust($color, $saturation: $amount, $space: hsl);
217
+ }
218
+
219
+ /// 明度调整(HSL 空间)。
220
+ @function fanui-lighten($color, $amount) {
221
+ @return color.adjust($color, $lightness: $amount, $space: hsl);
222
+ }
223
+
224
+ /// 依据模式推导「悬停色」:浅色模式压暗、深色模式提亮。
225
+ @function fanui-state-color($color, $mode: light, $amount: 8%) {
226
+ @if $mode == dark {
227
+ @return fanui-tint($color, $amount);
228
+ }
229
+ @return fanui-shade($color, $amount);
230
+ }
231
+
232
+ // -----------------------------------------------------------------------------
233
+ // 3. Map / 设计令牌读取
234
+ // -----------------------------------------------------------------------------
235
+
236
+ /// 安全地深层读取 map 值,路径不存在时抛出可定位的错误。
237
+ /// @example fanui-map-deep($colors, "primary", 500)
238
+ @function fanui-map-deep($map, $keys...) {
239
+ $cursor: $map;
240
+ @each $key in $keys {
241
+ @if meta.type-of($cursor) != "map" or not map.has-key($cursor, $key) {
242
+ @error "fanUI: 在令牌表中找不到路径 `#{list.join($keys, ' > ')}`(当前键:#{$key})。";
243
+ }
244
+ $cursor: map.get($cursor, $key);
245
+ }
246
+ @return $cursor;
247
+ }
248
+
249
+ /// 读取调色板色阶:fanui-palette($colors, primary, 500)
250
+ @function fanui-palette($palette, $name, $tone: 500) {
251
+ @return fanui-map-deep($palette, $name, $tone);
252
+ }
253
+
254
+ /// 读取间距令牌:fanui-space($spacers, 4)
255
+ @function fanui-space($spacers, $key) {
256
+ @return fanui-map-deep($spacers, $key);
257
+ }
258
+
259
+ /// 读取字号令牌。
260
+ @function fanui-font-size($sizes, $key) {
261
+ @return fanui-map-deep($sizes, $key);
262
+ }
263
+
264
+ /// 读取断点值。
265
+ @function fanui-breakpoint($breakpoints, $name) {
266
+ @return fanui-map-deep($breakpoints, $name);
267
+ }
268
+
269
+ /// 生成 keyframes / class 名安全化:替换 `.` 与 `%`。
270
+ @function fanui-slug($value) {
271
+ $s: "#{$value}";
272
+ $s: string.replace($s, ".", "-");
273
+ $s: string.replace($s, "%", "p");
274
+ @return $s;
275
+ }
276
+
277
+ // -----------------------------------------------------------------------------
278
+ // 4. CSS 自定义属性引用
279
+ // -----------------------------------------------------------------------------
280
+
281
+ /// 生成 `var(--fanui-*)` 引用,可带兜底值。
282
+ /// @example fanui-var("color-primary") => var(--fanui-color-primary)
283
+ /// @example fanui-var("radius", 6px) => var(--fanui-radius, 6px)
284
+ @function fanui-var($name, $fallback: null) {
285
+ @if $fallback == null {
286
+ @return var(--fanui-#{$name});
287
+ }
288
+ @return var(--fanui-#{$name}, #{$fallback});
289
+ }
290
+
291
+ /// 生成带命名空间的 `var()`(多级令牌,如 --fanui-color-primary-500)。
292
+ @function fanui-var-ns($names...) {
293
+ @return var(--fanui-#{list.join($names, "-")});
294
+ }
295
+
296
+ /// 生成 `calc()` 表达式,自动处理单位。
297
+ /// @example fanui-calc("100%", "-", 24px) => calc(100% - 24px)
298
+ @function fanui-calc($a, $op, $b) {
299
+ @return calc(#{$a} #{$op} #{$b});
300
+ }
301
+
302
+ /// 生成尺寸简写。
303
+ @function fanui-size-value($value) {
304
+ @if $value == null or $value == 0 {
305
+ @return 0;
306
+ } @else {
307
+ @return $value;
308
+ }
309
+ }
310
+
311
+ /// 生成断点中缀(用于拼接响应式类名)。
312
+ /// @example fanui-bp-infix("md") => "-md";fanui-bp-infix("xs") => ""
313
+ @function fanui-bp-infix($name) {
314
+ @if $name == "xs" {
315
+ @return "";
316
+ } @else {
317
+ @return "-#{$name}";
318
+ }
319
+ }