@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,351 @@
1
+ // =============================================================================
2
+ // fanUI · 按钮 Button
3
+ // -----------------------------------------------------------------------------
4
+ // 结构(BEM):
5
+ // .fanui-btn 基础类
6
+ // .fanui-btn__icon 图标槽
7
+ // .fanui-btn--<variant> 实心变体:primary/accent/success/warning/danger/info
8
+ // .fanui-btn--<size> xs/sm/md/lg/xl
9
+ // .fanui-btn--outline 描边风格(配合变体色)
10
+ // .fanui-btn--ghost / --text / --link
11
+ // .fanui-btn--block / --square / --pill / --loading
12
+ // 状态:.is-loading / .is-active / :disabled / .is-disabled
13
+ // 组合:.fanui-btn-group
14
+ // =============================================================================
15
+
16
+ @use "sass:map";
17
+ @use "../functions" as fn;
18
+ @use "../variables" as v;
19
+ @use "../mixins" as mx;
20
+
21
+ .fanui-btn {
22
+ // ---- 可变令牌(默认值 = primary 实心)----
23
+ --fanui-btn-bg: #{fn.fanui-var("primary")};
24
+ --fanui-btn-fg: #{fn.fanui-var("primary-fg", #fff)};
25
+ --fanui-btn-border: #{fn.fanui-var("primary")};
26
+ --fanui-btn-hover-bg: #{fn.fanui-var("primary-hover")};
27
+ --fanui-btn-hover-fg: #{fn.fanui-var("primary-fg", #fff)};
28
+ --fanui-btn-hover-border: #{fn.fanui-var("primary-hover")};
29
+ --fanui-btn-active-bg: #{fn.fanui-var("primary-active")};
30
+ --fanui-btn-active-fg: #{fn.fanui-var("primary-fg", #fff)};
31
+ --fanui-btn-active-border: #{fn.fanui-var("primary-active")};
32
+ --fanui-btn-ring: #{fn.fanui-var("primary-ring")};
33
+ --fanui-btn-height: #{fn.fanui-var("control-h", v.$fanui-control-height-base)};
34
+ --fanui-btn-padding-x: #{fn.fanui-var("control-px", v.$fanui-control-padding-x)};
35
+ --fanui-btn-font-size: #{fn.fanui-var("font-size-base")};
36
+ --fanui-btn-radius: #{fn.fanui-var("radius-base")};
37
+ --fanui-btn-gap: 6px;
38
+
39
+ position: relative;
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ gap: var(--fanui-btn-gap);
44
+ min-height: var(--fanui-btn-height);
45
+ padding: 0 var(--fanui-btn-padding-x);
46
+ font-family: inherit;
47
+ font-size: var(--fanui-btn-font-size);
48
+ font-weight: map.get(v.$fanui-font-weights, "medium");
49
+ line-height: 1;
50
+ white-space: nowrap;
51
+ vertical-align: middle;
52
+ text-decoration: none;
53
+ text-align: center;
54
+ color: var(--fanui-btn-fg);
55
+ background-color: var(--fanui-btn-bg);
56
+ border: 1px solid var(--fanui-btn-border);
57
+ border-radius: var(--fanui-btn-radius);
58
+ cursor: pointer;
59
+ user-select: none;
60
+ box-sizing: border-box;
61
+ overflow: hidden;
62
+ @include mx.fanui-transition((color, background-color, border-color, box-shadow, transform, opacity), v.$fanui-duration-fast);
63
+ @include mx.fanui-appearance-none();
64
+
65
+ // ---- hover ----
66
+ &:hover:not(:disabled):not(.is-disabled) {
67
+ color: var(--fanui-btn-hover-fg);
68
+ background-color: var(--fanui-btn-hover-bg);
69
+ border-color: var(--fanui-btn-hover-border);
70
+ text-decoration: none;
71
+ }
72
+
73
+ // ---- active ----
74
+ &:active:not(:disabled):not(.is-disabled),
75
+ &.is-active {
76
+ color: var(--fanui-btn-active-fg);
77
+ background-color: var(--fanui-btn-active-bg);
78
+ border-color: var(--fanui-btn-active-border);
79
+ }
80
+
81
+ // ---- focus ----
82
+ &:focus-visible {
83
+ outline: 0;
84
+ box-shadow: 0 0 0 var(--fanui-btn-ring);
85
+ }
86
+
87
+ // ---- 图标 ----
88
+ > svg,
89
+ .fanui-btn__icon {
90
+ flex: 0 0 auto;
91
+ width: 1em;
92
+ height: 1em;
93
+ font-size: 1.15em;
94
+ line-height: 1;
95
+ display: inline-flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ pointer-events: none;
99
+ }
100
+
101
+ @include mx.fanui-disabled();
102
+
103
+ &[aria-busy="true"] { pointer-events: none; }
104
+ }
105
+
106
+ // -----------------------------------------------------------------------------
107
+ // 1. 实心变体
108
+ // -----------------------------------------------------------------------------
109
+
110
+ @each $name, $color in v.$fanui-theme-colors {
111
+ .fanui-btn--#{$name} {
112
+ --fanui-btn-bg: #{fn.fanui-var("#{$name}", $color)};
113
+ --fanui-btn-fg: #{fn.fanui-var("#{$name}-fg", fn.fanui-contrast($color))};
114
+ --fanui-btn-border: #{fn.fanui-var("#{$name}", $color)};
115
+ --fanui-btn-hover-bg: #{fn.fanui-var("#{$name}-hover", fn.fanui-shade($color, 10%))};
116
+ --fanui-btn-hover-fg: #{fn.fanui-var("#{$name}-fg", fn.fanui-contrast($color))};
117
+ --fanui-btn-hover-border: #{fn.fanui-var("#{$name}-hover", fn.fanui-shade($color, 10%))};
118
+ --fanui-btn-active-bg: #{fn.fanui-var("#{$name}-active", fn.fanui-shade($color, 18%))};
119
+ --fanui-btn-active-fg: #{fn.fanui-var("#{$name}-fg", fn.fanui-contrast($color))};
120
+ --fanui-btn-active-border: #{fn.fanui-var("#{$name}-active", fn.fanui-shade($color, 18%))};
121
+ --fanui-btn-ring: #{fn.fanui-var("#{$name}-ring", fn.fanui-alpha($color, v.$fanui-focus-ring-alpha))};
122
+ }
123
+ }
124
+
125
+ // 中性 / 默认(次要按钮:浅灰底)
126
+ .fanui-btn--neutral,
127
+ .fanui-btn--default {
128
+ --fanui-btn-bg: #{fn.fanui-var("color-surface")};
129
+ --fanui-btn-fg: #{fn.fanui-var("color-text")};
130
+ --fanui-btn-border: #{fn.fanui-var("color-border-strong")};
131
+ --fanui-btn-hover-bg: #{fn.fanui-var("color-hover")};
132
+ --fanui-btn-hover-fg: #{fn.fanui-var("color-text-strong")};
133
+ --fanui-btn-hover-border: #{fn.fanui-var("color-border-strong")};
134
+ --fanui-btn-active-bg: #{fn.fanui-var("color-active")};
135
+ --fanui-btn-active-fg: #{fn.fanui-var("color-text-strong")};
136
+ --fanui-btn-active-border: #{fn.fanui-var("color-border-strong")};
137
+ --fanui-btn-ring: #{fn.fanui-alpha(v.$fanui-primary, 0.28)};
138
+ }
139
+
140
+ // 白色(用于深色/彩色背景之上)
141
+ .fanui-btn--white {
142
+ @include mx.fanui-button-variant(#ffffff, fn.fanui-var("color-text-strong"), #ffffff);
143
+ }
144
+
145
+ // -----------------------------------------------------------------------------
146
+ // 2. 描边 / 幽灵 / 文字 / 链接
147
+ // -----------------------------------------------------------------------------
148
+
149
+ @each $name, $color in v.$fanui-theme-colors {
150
+ .fanui-btn--outline.fanui-btn--#{$name} {
151
+ --fanui-btn-bg: transparent;
152
+ --fanui-btn-fg: #{fn.fanui-var("#{$name}", $color)};
153
+ --fanui-btn-border: #{fn.fanui-var("#{$name}", $color)};
154
+ --fanui-btn-hover-bg: #{fn.fanui-var("#{$name}", $color)};
155
+ --fanui-btn-hover-fg: #{fn.fanui-var("#{$name}-fg", fn.fanui-contrast($color))};
156
+ --fanui-btn-hover-border: #{fn.fanui-var("#{$name}", $color)};
157
+ --fanui-btn-active-bg: #{fn.fanui-var("#{$name}-active", fn.fanui-shade($color, 18%))};
158
+ --fanui-btn-active-fg: #{fn.fanui-var("#{$name}-fg", fn.fanui-contrast($color))};
159
+ --fanui-btn-active-border: #{fn.fanui-var("#{$name}-active", fn.fanui-shade($color, 18%))};
160
+ --fanui-btn-ring: #{fn.fanui-var("#{$name}-ring", fn.fanui-alpha($color, v.$fanui-focus-ring-alpha))};
161
+ }
162
+ }
163
+
164
+ .fanui-btn--ghost,
165
+ .fanui-btn--text {
166
+ --fanui-btn-bg: transparent;
167
+ --fanui-btn-fg: #{fn.fanui-var("color-text-muted")};
168
+ --fanui-btn-border: transparent;
169
+ --fanui-btn-hover-bg: #{fn.fanui-var("color-hover")};
170
+ --fanui-btn-hover-fg: #{fn.fanui-var("color-text")};
171
+ --fanui-btn-hover-border: transparent;
172
+ --fanui-btn-active-bg: #{fn.fanui-var("color-active")};
173
+ --fanui-btn-active-fg: #{fn.fanui-var("color-text-strong")};
174
+ --fanui-btn-active-border: transparent;
175
+ --fanui-btn-ring: #{fn.fanui-var("primary-ring")};
176
+ }
177
+
178
+ @each $name, $color in v.$fanui-theme-colors {
179
+ .fanui-btn--ghost.fanui-btn--#{$name},
180
+ .fanui-btn--text.fanui-btn--#{$name} {
181
+ --fanui-btn-bg: transparent;
182
+ --fanui-btn-fg: #{fn.fanui-var("#{$name}", $color)};
183
+ --fanui-btn-border: transparent;
184
+ --fanui-btn-hover-bg: #{fn.fanui-var("#{$name}-soft", fn.fanui-alpha($color, 0.10))};
185
+ --fanui-btn-hover-fg: #{fn.fanui-var("#{$name}-hover", fn.fanui-shade($color, 8%))};
186
+ --fanui-btn-hover-border: transparent;
187
+ --fanui-btn-active-bg: #{fn.fanui-alpha($color, 0.18)};
188
+ --fanui-btn-active-fg: #{fn.fanui-var("#{$name}-active", fn.fanui-shade($color, 16%))};
189
+ --fanui-btn-active-border: transparent;
190
+ --fanui-btn-ring: #{fn.fanui-var("#{$name}-ring", fn.fanui-alpha($color, v.$fanui-focus-ring-alpha))};
191
+ }
192
+ }
193
+
194
+ .fanui-btn--link {
195
+ --fanui-btn-bg: transparent;
196
+ --fanui-btn-fg: #{fn.fanui-var("primary")};
197
+ --fanui-btn-border: transparent;
198
+ --fanui-btn-hover-bg: transparent;
199
+ --fanui-btn-hover-fg: #{fn.fanui-var("primary-hover")};
200
+ --fanui-btn-hover-border: transparent;
201
+ --fanui-btn-active-bg: transparent;
202
+ --fanui-btn-active-fg: #{fn.fanui-var("primary-active")};
203
+ --fanui-btn-active-border: transparent;
204
+
205
+ padding: 0;
206
+ min-height: auto;
207
+ text-decoration: none;
208
+
209
+ &:hover { text-decoration: underline; }
210
+ }
211
+
212
+ // -----------------------------------------------------------------------------
213
+ // 3. 尺寸
214
+ // -----------------------------------------------------------------------------
215
+
216
+ .fanui-btn--xs {
217
+ @include mx.fanui-button-size(24px, 8px, fn.fanui-var("font-size-xs"), fn.fanui-var("radius-sm"));
218
+ --fanui-btn-gap: 4px;
219
+ }
220
+ .fanui-btn--sm {
221
+ @include mx.fanui-button-size(28px, 10px, fn.fanui-var("font-size-sm"));
222
+ --fanui-btn-gap: 4px;
223
+ }
224
+ .fanui-btn--md {
225
+ @include mx.fanui-button-size(32px, 12px, fn.fanui-var("font-size-base"));
226
+ }
227
+ .fanui-btn--base, .fanui-btn--lg {
228
+ @include mx.fanui-button-size(40px, 16px, fn.fanui-var("font-size-md"));
229
+ }
230
+ .fanui-btn--xl {
231
+ @include mx.fanui-button-size(48px, 22px, fn.fanui-var("font-size-lg"), fn.fanui-var("radius-md"));
232
+ }
233
+
234
+ // -----------------------------------------------------------------------------
235
+ // 4. 形状 / 布局修饰
236
+ // -----------------------------------------------------------------------------
237
+
238
+ .fanui-btn--block {
239
+ display: flex;
240
+ width: 100%;
241
+ }
242
+
243
+ .fanui-btn--square {
244
+ --fanui-btn-padding-x: 0;
245
+ width: var(--fanui-btn-height);
246
+ padding: 0;
247
+ flex: 0 0 auto;
248
+ }
249
+
250
+ .fanui-btn--circle {
251
+ --fanui-btn-padding-x: 0;
252
+ width: var(--fanui-btn-height);
253
+ padding: 0;
254
+ border-radius: 9999px;
255
+ flex: 0 0 auto;
256
+ }
257
+
258
+ .fanui-btn--pill { --fanui-btn-radius: 9999px; }
259
+ .fanui-btn--sharp { --fanui-btn-radius: 0; }
260
+
261
+ .fanui-btn--icon-start { flex-direction: row-reverse; }
262
+ .fanui-btn--icon-end { flex-direction: row; }
263
+
264
+ // -----------------------------------------------------------------------------
265
+ // 5. 加载态
266
+ // -----------------------------------------------------------------------------
267
+
268
+ .fanui-btn--loading,
269
+ .fanui-btn.is-loading {
270
+ pointer-events: none;
271
+ color: transparent !important;
272
+
273
+ &::after {
274
+ content: "";
275
+ position: absolute;
276
+ top: 50%;
277
+ left: 50%;
278
+ width: 1em;
279
+ height: 1em;
280
+ margin: -0.5em 0 0 -0.5em;
281
+ border: 2px solid currentColor;
282
+ border-top-color: transparent;
283
+ border-radius: 50%;
284
+ color: var(--fanui-btn-fg);
285
+ animation: fanui-spin 700ms linear infinite;
286
+ }
287
+
288
+ > * { visibility: hidden; }
289
+ }
290
+
291
+ // -----------------------------------------------------------------------------
292
+ // 6. 按钮组
293
+ // -----------------------------------------------------------------------------
294
+
295
+ .fanui-btn-group {
296
+ display: inline-flex;
297
+ vertical-align: middle;
298
+ border-radius: fn.fanui-var("radius-base");
299
+ overflow: hidden;
300
+
301
+ > .fanui-btn {
302
+ border-radius: 0;
303
+ margin-inline-start: -1px;
304
+ flex: 1 1 auto;
305
+ }
306
+
307
+ > .fanui-btn:first-child {
308
+ margin-inline-start: 0;
309
+ border-start-start-radius: fn.fanui-var("radius-base");
310
+ border-end-start-radius: fn.fanui-var("radius-base");
311
+ }
312
+
313
+ > .fanui-btn:last-child {
314
+ border-start-end-radius: fn.fanui-var("radius-base");
315
+ border-end-end-radius: fn.fanui-var("radius-base");
316
+ }
317
+
318
+ > .fanui-btn:hover,
319
+ > .fanui-btn:focus-visible,
320
+ > .fanui-btn.is-active {
321
+ z-index: 1;
322
+ }
323
+
324
+ &--pill { border-radius: 9999px; }
325
+
326
+ &--vertical {
327
+ flex-direction: column;
328
+
329
+ > .fanui-btn {
330
+ margin-inline-start: 0;
331
+ margin-top: -1px;
332
+ width: 100%;
333
+ }
334
+
335
+ > .fanui-btn:first-child {
336
+ border-radius: fn.fanui-var("radius-base") fn.fanui-var("radius-base") 0 0;
337
+ }
338
+
339
+ > .fanui-btn:last-child {
340
+ border-radius: 0 0 fn.fanui-var("radius-base") fn.fanui-var("radius-base");
341
+ }
342
+ }
343
+ }
344
+
345
+ // 工具栏(按钮组之间自动留白)
346
+ .fanui-btn-toolbar {
347
+ display: flex;
348
+ flex-wrap: wrap;
349
+ align-items: center;
350
+ gap: fn.fanui-var("space-3");
351
+ }