@star-ai/star-ui 0.0.2

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.
@@ -0,0 +1,404 @@
1
+ <template>
2
+ <view class="star-input" :class="inputClasses">
3
+ <!-- 前置内容 -->
4
+ <view v-if="$slots.prepend || prepend" class="star-input__prepend">
5
+ <slot name="prepend">
6
+ <text v-if="prepend" class="star-input__prepend-text">{{ prepend }}</text>
7
+ </slot>
8
+ </view>
9
+
10
+ <!-- 输入框主体 -->
11
+ <view class="star-input__wrapper">
12
+ <!-- 前置图标 -->
13
+ <text
14
+ v-if="prefixIcon"
15
+ class="star-input__prefix-icon"
16
+ :class="prefixIcon"
17
+ @click="handlePrefixIconClick"
18
+ ></text>
19
+
20
+ <!-- 输入框 -->
21
+ <input
22
+ class="star-input__inner"
23
+ :type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
24
+ :value="currentValue"
25
+ :placeholder="placeholder"
26
+ :disabled="disabled"
27
+ :maxlength="maxlength"
28
+ :focus="focus"
29
+ :confirm-type="confirmType"
30
+ :placeholder-style="placeholderStyle"
31
+ :placeholder-class="placeholderClass"
32
+ :cursor-spacing="cursorSpacing"
33
+ @input="handleInput"
34
+ @focus="handleFocus"
35
+ @blur="handleBlur"
36
+ @confirm="handleConfirm"
37
+ @keyboardheightchange="handleKeyboardHeightChange"
38
+ />
39
+
40
+ <!-- 清除按钮 -->
41
+ <view
42
+ v-if="clearable && currentValue && !disabled"
43
+ class="star-input__clear"
44
+ @click="handleClear"
45
+ >
46
+ <text class="star-icon-close"></text>
47
+ </view>
48
+
49
+ <!-- 密码可见切换按钮 -->
50
+ <view
51
+ v-if="showPassword && currentValue"
52
+ class="star-input__password-toggle"
53
+ @click="togglePasswordVisible"
54
+ >
55
+ <text :class="passwordVisible ? 'star-icon-eye-open' : 'star-icon-eye-close'"></text>
56
+ </view>
57
+
58
+ <!-- 后置图标 -->
59
+ <text
60
+ v-if="suffixIcon"
61
+ class="star-input__suffix-icon"
62
+ :class="suffixIcon"
63
+ @click="handleSuffixIconClick"
64
+ ></text>
65
+ </view>
66
+
67
+ <!-- 后置内容 -->
68
+ <view v-if="$slots.append || append" class="star-input__append">
69
+ <slot name="append">
70
+ <text v-if="append" class="star-input__append-text">{{ append }}</text>
71
+ </slot>
72
+ </view>
73
+ </view>
74
+ </template>
75
+
76
+ <script>
77
+ export default {
78
+ name: 'StarInput',
79
+
80
+ props: {
81
+ // 输入框类型
82
+ type: {
83
+ type: String,
84
+ default: 'text'
85
+ },
86
+
87
+ // 绑定值
88
+ value: {
89
+ type: [String, Number],
90
+ default: ''
91
+ },
92
+
93
+ // 原生属性
94
+ placeholder: {
95
+ type: String,
96
+ default: ''
97
+ },
98
+
99
+ disabled: {
100
+ type: Boolean,
101
+ default: false
102
+ },
103
+
104
+ maxlength: {
105
+ type: [String, Number],
106
+ default: 140
107
+ },
108
+
109
+ focus: {
110
+ type: Boolean,
111
+ default: false
112
+ },
113
+
114
+ confirmType: {
115
+ type: String,
116
+ default: 'done'
117
+ },
118
+
119
+ placeholderStyle: {
120
+ type: String,
121
+ default: ''
122
+ },
123
+
124
+ placeholderClass: {
125
+ type: String,
126
+ default: ''
127
+ },
128
+
129
+ cursorSpacing: {
130
+ type: [String, Number],
131
+ default: 0
132
+ },
133
+
134
+ // 自定义属性
135
+ size: {
136
+ type: String,
137
+ default: 'medium',
138
+ validator: (value) => ['mini', 'small', 'medium', 'large'].includes(value)
139
+ },
140
+
141
+ clearable: {
142
+ type: Boolean,
143
+ default: false
144
+ },
145
+
146
+ showPassword: {
147
+ type: Boolean,
148
+ default: false
149
+ },
150
+
151
+ prefixIcon: {
152
+ type: String,
153
+ default: ''
154
+ },
155
+
156
+ suffixIcon: {
157
+ type: String,
158
+ default: ''
159
+ },
160
+
161
+ prepend: {
162
+ type: String,
163
+ default: ''
164
+ },
165
+
166
+ append: {
167
+ type: String,
168
+ default: ''
169
+ },
170
+
171
+ readonly: {
172
+ type: Boolean,
173
+ default: false
174
+ }
175
+ },
176
+
177
+ data() {
178
+ return {
179
+ currentValue: this.value,
180
+ isFocused: false,
181
+ passwordVisible: false
182
+ }
183
+ },
184
+
185
+ computed: {
186
+ inputClasses() {
187
+ return [
188
+ `star-input--${this.size}`,
189
+ {
190
+ 'star-input--disabled': this.disabled,
191
+ 'star-input--focused': this.isFocused,
192
+ 'star-input--with-prepend': this.prepend || this.$slots.prepend,
193
+ 'star-input--with-append': this.append || this.$slots.append,
194
+ 'star-input--readonly': this.readonly
195
+ }
196
+ ]
197
+ }
198
+ },
199
+
200
+ watch: {
201
+ value(newVal) {
202
+ this.currentValue = newVal
203
+ }
204
+ },
205
+
206
+ methods: {
207
+ handleInput(event) {
208
+ const value = event.detail.value
209
+ this.currentValue = value
210
+ this.$emit('input', value)
211
+ this.$emit('change', value)
212
+ },
213
+
214
+ handleFocus(event) {
215
+ this.isFocused = true
216
+ this.$emit('focus', event)
217
+ },
218
+
219
+ handleBlur(event) {
220
+ this.isFocused = false
221
+ this.$emit('blur', event)
222
+ },
223
+
224
+ handleConfirm(event) {
225
+ this.$emit('confirm', event)
226
+ },
227
+
228
+ handleKeyboardHeightChange(event) {
229
+ this.$emit('keyboardheightchange', event)
230
+ },
231
+
232
+ handleClear() {
233
+ this.currentValue = ''
234
+ this.$emit('input', '')
235
+ this.$emit('change', '')
236
+ this.$emit('clear')
237
+ },
238
+
239
+ togglePasswordVisible() {
240
+ this.passwordVisible = !this.passwordVisible
241
+ },
242
+
243
+ handlePrefixIconClick() {
244
+ this.$emit('click-prefix')
245
+ },
246
+
247
+ handleSuffixIconClick() {
248
+ this.$emit('click-suffix')
249
+ }
250
+ }
251
+ }
252
+ </script>
253
+
254
+ <style lang="scss" scoped>
255
+ @import "../../styles/variables.scss";
256
+
257
+ .star-input {
258
+ display: inline-flex;
259
+ width: 100%;
260
+ font-size: $font-size-base;
261
+ line-height: normal;
262
+
263
+ &__prepend,
264
+ &__append {
265
+ display: flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ padding: 0 12px;
269
+ background-color: $bg-color-grey;
270
+ border: 1px solid $border-color;
271
+ white-space: nowrap;
272
+
273
+ &-text {
274
+ color: $text-color-secondary;
275
+ }
276
+ }
277
+
278
+ &__prepend {
279
+ border-right: 0;
280
+ border-radius: $border-radius-base 0 0 $border-radius-base;
281
+ }
282
+
283
+ &__append {
284
+ border-left: 0;
285
+ border-radius: 0 $border-radius-base $border-radius-base 0;
286
+ }
287
+
288
+ &__wrapper {
289
+ display: flex;
290
+ align-items: center;
291
+ flex: 1;
292
+ position: relative;
293
+ padding: 0 12px;
294
+ border: 1px solid $border-color;
295
+ border-radius: $border-radius-base;
296
+ background-color: $bg-color;
297
+ transition: border-color 0.3s;
298
+
299
+ .star-input--with-prepend & {
300
+ border-top-left-radius: 0;
301
+ border-bottom-left-radius: 0;
302
+ border-left: 0;
303
+ }
304
+
305
+ .star-input--with-append & {
306
+ border-top-right-radius: 0;
307
+ border-bottom-right-radius: 0;
308
+ border-right: 0;
309
+ }
310
+ }
311
+
312
+ &--focused &__wrapper {
313
+ border-color: $primary-color;
314
+ }
315
+
316
+ &--disabled &__wrapper {
317
+ background-color: $bg-color-grey;
318
+ cursor: not-allowed;
319
+ }
320
+
321
+ &__inner {
322
+ flex: 1;
323
+ width: 100%;
324
+ height: 100%;
325
+ padding: 0;
326
+ border: none;
327
+ outline: none;
328
+ background: transparent;
329
+ font-size: inherit;
330
+ color: $text-color;
331
+
332
+ .star-input--disabled & {
333
+ color: $text-color-disabled;
334
+ cursor: not-allowed;
335
+ }
336
+
337
+ &::placeholder {
338
+ color: $text-color-light;
339
+ }
340
+ }
341
+
342
+ &__prefix-icon,
343
+ &__suffix-icon {
344
+ font-family: "star-icon-font" !important;
345
+ color: $text-color-light;
346
+ font-size: 18px;
347
+ cursor: pointer;
348
+ transition: color 0.3s;
349
+
350
+ &:hover {
351
+ color: $text-color;
352
+ }
353
+ }
354
+
355
+ &__prefix-icon {
356
+ margin-right: 8px;
357
+ }
358
+
359
+ &__suffix-icon {
360
+ margin-left: 8px;
361
+ }
362
+
363
+ &__clear,
364
+ &__password-toggle {
365
+ display: flex;
366
+ align-items: center;
367
+ justify-content: center;
368
+ width: 20px;
369
+ height: 20px;
370
+ margin-left: 8px;
371
+ color: $text-color-light;
372
+ cursor: pointer;
373
+ transition: color 0.3s;
374
+
375
+ &:hover {
376
+ color: $text-color;
377
+ }
378
+
379
+ .star-icon-close,
380
+ .star-icon-eye-open,
381
+ .star-icon-eye-close {
382
+ font-family: "star-icon-font" !important;
383
+ font-size: 16px;
384
+ }
385
+ }
386
+
387
+ // 尺寸
388
+ &--mini &__wrapper {
389
+ height: 24px;
390
+ }
391
+
392
+ &--small &__wrapper {
393
+ height: 32px;
394
+ }
395
+
396
+ &--medium &__wrapper {
397
+ height: 40px;
398
+ }
399
+
400
+ &--large &__wrapper {
401
+ height: 48px;
402
+ }
403
+ }
404
+ </style>
@@ -0,0 +1,7 @@
1
+ import StarInput from './Input.vue'
2
+
3
+ StarInput.install = function(Vue) {
4
+ Vue.component(StarInput.name, StarInput)
5
+ }
6
+
7
+ export default StarInput
@@ -0,0 +1,64 @@
1
+ // 自动导入所有组件(使用CommonJS语法,兼容Webpack环境)
2
+ const packageJson = require('../../package.json')
3
+
4
+ // 使用require.context自动扫描components目录下的所有组件(Webpack环境)
5
+ const requireComponent = require.context('./components', true, /index\.js$/)
6
+
7
+ // 组件列表
8
+ const components = requireComponent.keys().map(filePath => {
9
+ // 获取组件配置
10
+ const componentConfig = requireComponent(filePath)
11
+
12
+ // 获取组件的默认导出
13
+ return componentConfig.default || componentConfig
14
+ })
15
+
16
+ // 安装函数
17
+ const install = function(Vue, opts = {}) {
18
+ components.forEach(component => {
19
+ // 如果组件有install方法,使用install方法注册
20
+ if (component.install) {
21
+ Vue.use(component)
22
+ }
23
+ // 如果组件是Vue组件对象,直接注册
24
+ else if (component.name) {
25
+ Vue.component(component.name, component)
26
+ }
27
+ })
28
+
29
+ // 挂载全局方法
30
+ Vue.prototype.$MY_UI = {
31
+ size: opts.size || '',
32
+ zIndex: opts.zIndex || 2000
33
+ }
34
+ }
35
+
36
+ // 如果是浏览器环境且已引入Vue,则自动安装
37
+ if (typeof window !== 'undefined' && window.Vue) {
38
+ install(window.Vue)
39
+ }
40
+
41
+ // 创建导出对象
42
+ const StarUI = {
43
+ version: packageJson.version,
44
+ install
45
+ }
46
+
47
+ // 为StarUI添加所有组件属性,并添加单独的导出
48
+ components.forEach(component => {
49
+ if (component.name) {
50
+ StarUI[component.name] = component
51
+ module.exports[component.name] = component
52
+ }
53
+ })
54
+
55
+ // 导出模块
56
+ module.exports = StarUI
57
+
58
+ // 支持ES模块导入
59
+ module.exports.default = StarUI
60
+
61
+ // 支持AMD模块导入
62
+ if (typeof define === 'function' && define.amd) {
63
+ define(() => StarUI)
64
+ }
@@ -0,0 +1,102 @@
1
+ // 导入变量和混合器
2
+ @import './variables.scss';
3
+ @import './mixins.scss';
4
+
5
+ // 全局样式重置
6
+ .star-reset {
7
+ box-sizing: border-box;
8
+
9
+ *,
10
+ *::before,
11
+ *::after {
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ // 解决 H5 平台的一些问题
16
+ uni-page-body {
17
+ height: 100%;
18
+ }
19
+
20
+ uni-page-body,
21
+ uni-page-head {
22
+ background-color: $bg-color;
23
+ }
24
+ }
25
+
26
+ // 工具类
27
+ .star-text-center {
28
+ text-align: center;
29
+ }
30
+
31
+ .star-text-left {
32
+ text-align: left;
33
+ }
34
+
35
+ .star-text-right {
36
+ text-align: right;
37
+ }
38
+
39
+ .star-pull-left {
40
+ float: left;
41
+ }
42
+
43
+ .star-pull-right {
44
+ float: right;
45
+ }
46
+
47
+ .star-clearfix {
48
+ @include clearfix;
49
+ }
50
+
51
+ .star-ellipsis {
52
+ @include ellipsis;
53
+ }
54
+
55
+ // 间距工具类
56
+ @each $size, $value in (
57
+ xs: $spacing-xs,
58
+ sm: $spacing-sm,
59
+ base: $spacing-base,
60
+ lg: $spacing-lg,
61
+ xl: $spacing-xl
62
+ ) {
63
+ .star-m-#{$size} {
64
+ margin: $value;
65
+ }
66
+
67
+ .star-mt-#{$size} {
68
+ margin-top: $value;
69
+ }
70
+
71
+ .star-mr-#{$size} {
72
+ margin-right: $value;
73
+ }
74
+
75
+ .star-mb-#{$size} {
76
+ margin-bottom: $value;
77
+ }
78
+
79
+ .star-ml-#{$size} {
80
+ margin-left: $value;
81
+ }
82
+
83
+ .star-p-#{$size} {
84
+ padding: $value;
85
+ }
86
+
87
+ .star-pt-#{$size} {
88
+ padding-top: $value;
89
+ }
90
+
91
+ .star-pr-#{$size} {
92
+ padding-right: $value;
93
+ }
94
+
95
+ .star-pb-#{$size} {
96
+ padding-bottom: $value;
97
+ }
98
+
99
+ .star-pl-#{$size} {
100
+ padding-left: $value;
101
+ }
102
+ }
@@ -0,0 +1,84 @@
1
+ // 清除浮动
2
+ @mixin clearfix {
3
+ &::after {
4
+ content: "";
5
+ display: table;
6
+ clear: both;
7
+ }
8
+ }
9
+
10
+ // 单行省略
11
+ @mixin ellipsis {
12
+ overflow: hidden;
13
+ text-overflow: ellipsis;
14
+ white-space: nowrap;
15
+ }
16
+
17
+ // 多行省略
18
+ @mixin multi-ellipsis($lines: 2) {
19
+ display: -webkit-box;
20
+ overflow: hidden;
21
+ text-overflow: ellipsis;
22
+ -webkit-line-clamp: $lines;
23
+ -webkit-box-orient: vertical;
24
+ }
25
+
26
+ // 1px 边框(解决移动端 Retina 屏边框问题)
27
+ @mixin hairline($color: $border-color, $direction: bottom) {
28
+ position: relative;
29
+
30
+ &::after {
31
+ content: "";
32
+ position: absolute;
33
+ #{$direction}: 0;
34
+ left: 0;
35
+ right: 0;
36
+ height: 1px;
37
+ background-color: $color;
38
+ transform: scaleY(0.5);
39
+ transform-origin: 0 0;
40
+ }
41
+ }
42
+
43
+ // 禁用状态
44
+ @mixin disabled {
45
+ opacity: 0.6;
46
+ cursor: not-allowed;
47
+ pointer-events: none;
48
+ }
49
+
50
+ // 弹性布局快捷方式
51
+ @mixin flex-center {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ }
56
+
57
+ @mixin flex-between {
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: space-between;
61
+ }
62
+
63
+ @mixin flex-around {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-around;
67
+ }
68
+
69
+ // 响应式
70
+ @mixin respond-to($breakpoint) {
71
+ @if $breakpoint == 'xs' {
72
+ @media (max-width: 575px) { @content; }
73
+ } @else if $breakpoint == 'sm' {
74
+ @media (min-width: 576px) { @content; }
75
+ } @else if $breakpoint == 'md' {
76
+ @media (min-width: 768px) { @content; }
77
+ } @else if $breakpoint == 'lg' {
78
+ @media (min-width: 992px) { @content; }
79
+ } @else if $breakpoint == 'xl' {
80
+ @media (min-width: 1200px) { @content; }
81
+ } @else if $breakpoint == 'xxl' {
82
+ @media (min-width: 1600px) { @content; }
83
+ }
84
+ }
@@ -0,0 +1,64 @@
1
+ // 颜色系统
2
+ $white: #ffffff;
3
+ $black: #000000;
4
+
5
+ // 主色调
6
+ $primary-color: #2979ff;
7
+ $primary-color-light: #5cadff;
8
+ $primary-color-dark: #2b85e4;
9
+
10
+ // 功能色
11
+ $success-color: #19be6b;
12
+ $warning-color: #ff9900;
13
+ $error-color: #fa3534;
14
+ $info-color: #909399;
15
+
16
+ // 中性色
17
+ $text-color: #333333;
18
+ $text-color-secondary: #666666;
19
+ $text-color-light: #999999;
20
+ $text-color-disabled: #c0c4cc;
21
+
22
+ $bg-color: #ffffff;
23
+ $bg-color-grey: #f5f5f5;
24
+ $bg-color-hover: #f6f6f6;
25
+
26
+ $border-color: #e4e7ed;
27
+ $border-color-light: #ebeef5;
28
+
29
+ // 阴影
30
+ $box-shadow-base: 0 2px 12px rgba(0, 0, 0, 0.1);
31
+ $box-shadow-light: 0 2px 8px rgba(0, 0, 0, 0.09);
32
+ $box-shadow-dark: 0 2px 16px rgba(0, 0, 0, 0.2);
33
+
34
+ // 边框半径
35
+ $border-radius-base: 4px;
36
+ $border-radius-sm: 2px;
37
+ $border-radius-lg: 8px;
38
+ $border-radius-circle: 50%;
39
+
40
+ // 字体
41
+ $font-size-xs: 10px;
42
+ $font-size-sm: 12px;
43
+ $font-size-base: 14px;
44
+ $font-size-lg: 16px;
45
+ $font-size-xl: 18px;
46
+ $font-size-xxl: 20px;
47
+
48
+ // 间距
49
+ $spacing-xs: 4px;
50
+ $spacing-sm: 8px;
51
+ $spacing-base: 16px;
52
+ $spacing-lg: 24px;
53
+ $spacing-xl: 32px;
54
+
55
+ // 层级
56
+ $z-index-normal: 1;
57
+ $z-index-dropdown: 1000;
58
+ $z-index-sticky: 1020;
59
+ $z-index-fixed: 1030;
60
+ $z-index-modal-backdrop: 1040;
61
+ $z-index-modal: 1050;
62
+ $z-index-popover: 1060;
63
+ $z-index-tooltip: 1070;
64
+ $z-index-toast: 1080;