@ikun2274/spiritechoui 0.1.51 → 0.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.
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createElementVNode, toDisplayString, defineComponent, withDirectives, vModelDynamic, ref, vShow } from "vue";
7
+ import { openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createElementVNode, toDisplayString, defineComponent, withDirectives, vModelDynamic, ref, vShow, computed, provide, Fragment, renderList, inject, onMounted, createCommentVNode } from "vue";
8
8
  class MyUI {
9
9
  /**
10
10
  * 支持 app.use(MyUI) 注册的静态方法
@@ -59,7 +59,7 @@ const _export_sfc = (sfc, props) => {
59
59
  }
60
60
  return target;
61
61
  };
62
- const _sfc_main$2 = {
62
+ const _sfc_main$4 = {
63
63
  props: {
64
64
  // 文本样式类型
65
65
  textType: {
@@ -106,8 +106,8 @@ const _sfc_main$2 = {
106
106
  }
107
107
  }
108
108
  };
109
- const _hoisted_1$2 = ["disabled"];
110
- function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
109
+ const _hoisted_1$4 = ["disabled"];
110
+ function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
111
111
  return openBlock(), createElementBlock("button", {
112
112
  class: normalizeClass(["SpiritEchoBtn", [
113
113
  `SpiritEchoBtn--${$props.type}`,
@@ -124,10 +124,10 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
124
124
  style: normalizeStyle($props.textStyle)
125
125
  }, toDisplayString($props.text), 7)
126
126
  ])
127
- ], 14, _hoisted_1$2);
127
+ ], 14, _hoisted_1$4);
128
128
  }
129
- const speButton = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2]]);
130
- const _sfc_main$1 = defineComponent({
129
+ const speButton = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$4]]);
130
+ const _sfc_main$3 = defineComponent({
131
131
  name: "SpInput",
132
132
  props: {
133
133
  modelValue: {
@@ -242,10 +242,10 @@ const _sfc_main$1 = defineComponent({
242
242
  }
243
243
  });
244
244
  const SpInput_vue_vue_type_style_index_0_lang = "";
245
- const _hoisted_1$1 = { class: "SPInput-container" };
246
- const _hoisted_2$1 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
247
- function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
248
- return openBlock(), createElementBlock("div", _hoisted_1$1, [
245
+ const _hoisted_1$3 = { class: "SPInput-container" };
246
+ const _hoisted_2$2 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
247
+ function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
248
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
249
249
  withDirectives(createElementVNode("input", {
250
250
  type: _ctx.type,
251
251
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.inputValue = $event),
@@ -258,13 +258,13 @@ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
258
258
  onBlur: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("blur", $event)),
259
259
  onChange: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("change", $event)),
260
260
  class: "SPInput"
261
- }, null, 40, _hoisted_2$1), [
261
+ }, null, 40, _hoisted_2$2), [
262
262
  [vModelDynamic, _ctx.inputValue]
263
263
  ])
264
264
  ]);
265
265
  }
266
- const speinput = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
267
- const _sfc_main = defineComponent({
266
+ const speinput = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3]]);
267
+ const _sfc_main$2 = defineComponent({
268
268
  name: "SimpleCodeDemo",
269
269
  // 仅接收一个核心prop:源码字符串
270
270
  props: {
@@ -280,21 +280,21 @@ const _sfc_main = defineComponent({
280
280
  return { isShowCode };
281
281
  }
282
282
  });
283
- const SPEBlock_vue_vue_type_style_index_0_scoped_e0daeed3_lang = "";
284
- const _hoisted_1 = { class: "code-demo" };
285
- const _hoisted_2 = ["innerHTML"];
286
- const _hoisted_3 = { class: "code-area" };
287
- function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
288
- return openBlock(), createElementBlock("div", _hoisted_1, [
283
+ const SPEBlock_vue_vue_type_style_index_0_scoped_e583bfde_lang = "";
284
+ const _hoisted_1$2 = { class: "code-demo" };
285
+ const _hoisted_2$1 = ["innerHTML"];
286
+ const _hoisted_3$1 = { class: "code-area" };
287
+ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
288
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [
289
289
  createElementVNode("div", {
290
290
  class: "demo-preview",
291
291
  innerHTML: _ctx.sourceCode
292
- }, null, 8, _hoisted_2),
292
+ }, null, 8, _hoisted_2$1),
293
293
  createElementVNode("div", {
294
294
  class: "toggle-btn",
295
295
  onClick: _cache[0] || (_cache[0] = ($event) => _ctx.isShowCode = !_ctx.isShowCode)
296
296
  }, toDisplayString(_ctx.isShowCode ? "收起源码" : "查看源码"), 1),
297
- withDirectives(createElementVNode("div", _hoisted_3, [
297
+ withDirectives(createElementVNode("div", _hoisted_3$1, [
298
298
  createElementVNode("pre", null, [
299
299
  createElementVNode("code", null, toDisplayString(_ctx.sourceCode), 1)
300
300
  ])
@@ -303,21 +303,109 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
303
303
  ])
304
304
  ]);
305
305
  }
306
- const speblock = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-e0daeed3"]]);
306
+ const speblock = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-e583bfde"]]);
307
+ const Tabs_vue_vue_type_style_index_0_scoped_fe4030ae_lang = "";
308
+ const _sfc_main$1 = {
309
+ name: "Tabs",
310
+ props: {
311
+ modelValue: {
312
+ type: String,
313
+ required: true
314
+ }
315
+ },
316
+ emits: ["update:modelValue"],
317
+ setup(props, { emit }) {
318
+ const panes = ref([]);
319
+ const addPane = (pane) => {
320
+ panes.value.push(pane);
321
+ };
322
+ const activeName = computed(() => props.modelValue);
323
+ provide("TabsContext", {
324
+ activeName,
325
+ addPane
326
+ });
327
+ const handleTabClick = (name) => {
328
+ emit("update:modelValue", name);
329
+ };
330
+ return {
331
+ panes,
332
+ handleTabClick
333
+ };
334
+ }
335
+ };
336
+ const _hoisted_1$1 = { class: "tabs" };
337
+ const _hoisted_2 = { class: "tabs-header" };
338
+ const _hoisted_3 = ["onClick"];
339
+ const _hoisted_4 = { class: "tabs-content" };
340
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
341
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
342
+ createElementVNode("div", _hoisted_2, [
343
+ (openBlock(true), createElementBlock(Fragment, null, renderList($setup.panes, (pane) => {
344
+ return openBlock(), createElementBlock("div", {
345
+ key: pane.name,
346
+ class: normalizeClass(["tab-item", { active: $props.modelValue === pane.name }]),
347
+ onClick: ($event) => $setup.handleTabClick(pane.name)
348
+ }, toDisplayString(pane.label), 11, _hoisted_3);
349
+ }), 128))
350
+ ]),
351
+ createElementVNode("div", _hoisted_4, [
352
+ renderSlot(_ctx.$slots, "default", {}, void 0, true)
353
+ ])
354
+ ]);
355
+ }
356
+ const speTabs = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1], ["__scopeId", "data-v-fe4030ae"]]);
357
+ const TabPane_vue_vue_type_style_index_0_scoped_3fe96054_lang = "";
358
+ const _sfc_main = {
359
+ name: "TabPane",
360
+ props: {
361
+ name: {
362
+ type: String,
363
+ required: true
364
+ },
365
+ label: {
366
+ type: String,
367
+ required: true
368
+ }
369
+ },
370
+ setup(props) {
371
+ const TabsContext = inject("TabsContext");
372
+ const activeName = TabsContext.activeName;
373
+ onMounted(() => {
374
+ TabsContext.addPane({
375
+ name: props.name,
376
+ label: props.label
377
+ });
378
+ });
379
+ return {
380
+ activeName
381
+ };
382
+ }
383
+ };
384
+ const _hoisted_1 = {
385
+ key: 0,
386
+ class: "tab-pane"
387
+ };
388
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
389
+ return $setup.activeName === $props.name ? (openBlock(), createElementBlock("div", _hoisted_1, [
390
+ renderSlot(_ctx.$slots, "default", {}, void 0, true)
391
+ ])) : createCommentVNode("", true);
392
+ }
393
+ const speTabPane = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3fe96054"]]);
307
394
  const injector = new ComponentInjector(MyUI);
308
- injector.register("form", "speButton", speButton, {
395
+ injector.register("basic", "speButton", speButton, {
309
396
  type: "default",
310
397
  size: "medium"
311
398
  });
312
399
  injector.register("form", "speinput", speinput);
313
400
  injector.register("tool", "speblock", speblock);
401
+ injector.register("navigation", "speTabs", speTabs);
402
+ injector.register("navigation", "speTabPane", speTabPane);
314
403
  MyUI.install = (app) => {
315
- app.component("SPE-Button", MyUI.form.speButton({}));
404
+ app.component("SPE-Button", MyUI.basic.speButton({}));
316
405
  app.component("SPE-Input", MyUI.form.speinput({}));
317
- app.component(
318
- "SPE-Block",
319
- MyUI.tool.speblock({})
320
- );
406
+ app.component("SPE-Block", MyUI.tool.speblock({}));
407
+ app.component("SPE-Tabs", MyUI.navigation.speTabs({}));
408
+ app.component("SPE-TabPane", MyUI.navigation.speTabPane({}));
321
409
  };
322
410
  export {
323
411
  MyUI
@@ -62,7 +62,7 @@ var __publicField = (obj, key, value) => {
62
62
  }
63
63
  return target;
64
64
  };
65
- const _sfc_main$2 = {
65
+ const _sfc_main$4 = {
66
66
  props: {
67
67
  // 文本样式类型
68
68
  textType: {
@@ -109,8 +109,8 @@ var __publicField = (obj, key, value) => {
109
109
  }
110
110
  }
111
111
  };
112
- const _hoisted_1$2 = ["disabled"];
113
- function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
112
+ const _hoisted_1$4 = ["disabled"];
113
+ function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
114
114
  return vue.openBlock(), vue.createElementBlock("button", {
115
115
  class: vue.normalizeClass(["SpiritEchoBtn", [
116
116
  `SpiritEchoBtn--${$props.type}`,
@@ -127,10 +127,10 @@ var __publicField = (obj, key, value) => {
127
127
  style: vue.normalizeStyle($props.textStyle)
128
128
  }, vue.toDisplayString($props.text), 7)
129
129
  ])
130
- ], 14, _hoisted_1$2);
130
+ ], 14, _hoisted_1$4);
131
131
  }
132
- const speButton = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2]]);
133
- const _sfc_main$1 = vue.defineComponent({
132
+ const speButton = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$4]]);
133
+ const _sfc_main$3 = vue.defineComponent({
134
134
  name: "SpInput",
135
135
  props: {
136
136
  modelValue: {
@@ -245,10 +245,10 @@ var __publicField = (obj, key, value) => {
245
245
  }
246
246
  });
247
247
  const SpInput_vue_vue_type_style_index_0_lang = "";
248
- const _hoisted_1$1 = { class: "SPInput-container" };
249
- const _hoisted_2$1 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
250
- function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
251
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
248
+ const _hoisted_1$3 = { class: "SPInput-container" };
249
+ const _hoisted_2$2 = ["type", "placeholder", "disabled", "maxlength", "name", "readonly"];
250
+ function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
251
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
252
252
  vue.withDirectives(vue.createElementVNode("input", {
253
253
  type: _ctx.type,
254
254
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.inputValue = $event),
@@ -261,13 +261,13 @@ var __publicField = (obj, key, value) => {
261
261
  onBlur: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("blur", $event)),
262
262
  onChange: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("change", $event)),
263
263
  class: "SPInput"
264
- }, null, 40, _hoisted_2$1), [
264
+ }, null, 40, _hoisted_2$2), [
265
265
  [vue.vModelDynamic, _ctx.inputValue]
266
266
  ])
267
267
  ]);
268
268
  }
269
- const speinput = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
270
- const _sfc_main = vue.defineComponent({
269
+ const speinput = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3]]);
270
+ const _sfc_main$2 = vue.defineComponent({
271
271
  name: "SimpleCodeDemo",
272
272
  // 仅接收一个核心prop:源码字符串
273
273
  props: {
@@ -283,21 +283,21 @@ var __publicField = (obj, key, value) => {
283
283
  return { isShowCode };
284
284
  }
285
285
  });
286
- const SPEBlock_vue_vue_type_style_index_0_scoped_e0daeed3_lang = "";
287
- const _hoisted_1 = { class: "code-demo" };
288
- const _hoisted_2 = ["innerHTML"];
289
- const _hoisted_3 = { class: "code-area" };
290
- function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
291
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
286
+ const SPEBlock_vue_vue_type_style_index_0_scoped_e583bfde_lang = "";
287
+ const _hoisted_1$2 = { class: "code-demo" };
288
+ const _hoisted_2$1 = ["innerHTML"];
289
+ const _hoisted_3$1 = { class: "code-area" };
290
+ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
291
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
292
292
  vue.createElementVNode("div", {
293
293
  class: "demo-preview",
294
294
  innerHTML: _ctx.sourceCode
295
- }, null, 8, _hoisted_2),
295
+ }, null, 8, _hoisted_2$1),
296
296
  vue.createElementVNode("div", {
297
297
  class: "toggle-btn",
298
298
  onClick: _cache[0] || (_cache[0] = ($event) => _ctx.isShowCode = !_ctx.isShowCode)
299
299
  }, vue.toDisplayString(_ctx.isShowCode ? "收起源码" : "查看源码"), 1),
300
- vue.withDirectives(vue.createElementVNode("div", _hoisted_3, [
300
+ vue.withDirectives(vue.createElementVNode("div", _hoisted_3$1, [
301
301
  vue.createElementVNode("pre", null, [
302
302
  vue.createElementVNode("code", null, vue.toDisplayString(_ctx.sourceCode), 1)
303
303
  ])
@@ -306,21 +306,109 @@ var __publicField = (obj, key, value) => {
306
306
  ])
307
307
  ]);
308
308
  }
309
- const speblock = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-e0daeed3"]]);
309
+ const speblock = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-e583bfde"]]);
310
+ const Tabs_vue_vue_type_style_index_0_scoped_fe4030ae_lang = "";
311
+ const _sfc_main$1 = {
312
+ name: "Tabs",
313
+ props: {
314
+ modelValue: {
315
+ type: String,
316
+ required: true
317
+ }
318
+ },
319
+ emits: ["update:modelValue"],
320
+ setup(props, { emit }) {
321
+ const panes = vue.ref([]);
322
+ const addPane = (pane) => {
323
+ panes.value.push(pane);
324
+ };
325
+ const activeName = vue.computed(() => props.modelValue);
326
+ vue.provide("TabsContext", {
327
+ activeName,
328
+ addPane
329
+ });
330
+ const handleTabClick = (name) => {
331
+ emit("update:modelValue", name);
332
+ };
333
+ return {
334
+ panes,
335
+ handleTabClick
336
+ };
337
+ }
338
+ };
339
+ const _hoisted_1$1 = { class: "tabs" };
340
+ const _hoisted_2 = { class: "tabs-header" };
341
+ const _hoisted_3 = ["onClick"];
342
+ const _hoisted_4 = { class: "tabs-content" };
343
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
344
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
345
+ vue.createElementVNode("div", _hoisted_2, [
346
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($setup.panes, (pane) => {
347
+ return vue.openBlock(), vue.createElementBlock("div", {
348
+ key: pane.name,
349
+ class: vue.normalizeClass(["tab-item", { active: $props.modelValue === pane.name }]),
350
+ onClick: ($event) => $setup.handleTabClick(pane.name)
351
+ }, vue.toDisplayString(pane.label), 11, _hoisted_3);
352
+ }), 128))
353
+ ]),
354
+ vue.createElementVNode("div", _hoisted_4, [
355
+ vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
356
+ ])
357
+ ]);
358
+ }
359
+ const speTabs = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1], ["__scopeId", "data-v-fe4030ae"]]);
360
+ const TabPane_vue_vue_type_style_index_0_scoped_3fe96054_lang = "";
361
+ const _sfc_main = {
362
+ name: "TabPane",
363
+ props: {
364
+ name: {
365
+ type: String,
366
+ required: true
367
+ },
368
+ label: {
369
+ type: String,
370
+ required: true
371
+ }
372
+ },
373
+ setup(props) {
374
+ const TabsContext = vue.inject("TabsContext");
375
+ const activeName = TabsContext.activeName;
376
+ vue.onMounted(() => {
377
+ TabsContext.addPane({
378
+ name: props.name,
379
+ label: props.label
380
+ });
381
+ });
382
+ return {
383
+ activeName
384
+ };
385
+ }
386
+ };
387
+ const _hoisted_1 = {
388
+ key: 0,
389
+ class: "tab-pane"
390
+ };
391
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
392
+ return $setup.activeName === $props.name ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
393
+ vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
394
+ ])) : vue.createCommentVNode("", true);
395
+ }
396
+ const speTabPane = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3fe96054"]]);
310
397
  const injector = new ComponentInjector(MyUI);
311
- injector.register("form", "speButton", speButton, {
398
+ injector.register("basic", "speButton", speButton, {
312
399
  type: "default",
313
400
  size: "medium"
314
401
  });
315
402
  injector.register("form", "speinput", speinput);
316
403
  injector.register("tool", "speblock", speblock);
404
+ injector.register("navigation", "speTabs", speTabs);
405
+ injector.register("navigation", "speTabPane", speTabPane);
317
406
  MyUI.install = (app) => {
318
- app.component("SPE-Button", MyUI.form.speButton({}));
407
+ app.component("SPE-Button", MyUI.basic.speButton({}));
319
408
  app.component("SPE-Input", MyUI.form.speinput({}));
320
- app.component(
321
- "SPE-Block",
322
- MyUI.tool.speblock({})
323
- );
409
+ app.component("SPE-Block", MyUI.tool.speblock({}));
410
+ app.component("SPE-Tabs", MyUI.navigation.speTabs({}));
411
+ app.component("SPE-TabPane", MyUI.navigation.speTabPane({}));
324
412
  };
325
413
  exports2.MyUI = MyUI;
326
414
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
package/dist/style.css CHANGED
@@ -106,16 +106,16 @@
106
106
  }
107
107
  .SPInput:read-only {
108
108
  background-color: #f5f7fa;
109
- }.code-demo[data-v-e0daeed3] {
109
+ }.code-demo[data-v-e583bfde] {
110
110
  border: 1px solid rgba(221, 216, 216, 0.4666666667);
111
111
  margin: 10px 0;
112
112
  align-items: center;
113
113
  }
114
- .code-demo .demo-preview[data-v-e0daeed3] {
114
+ .code-demo .demo-preview[data-v-e583bfde] {
115
115
  padding: 20px;
116
116
  background: #ffffff;
117
117
  }
118
- .code-demo .toggle-btn[data-v-e0daeed3] {
118
+ .code-demo .toggle-btn[data-v-e583bfde] {
119
119
  padding: 8px;
120
120
  text-align: center;
121
121
  background: #ebecec;
@@ -123,14 +123,14 @@
123
123
  border-top: 1px solid #eee;
124
124
  user-select: none;
125
125
  }
126
- .code-demo .code-area[data-v-e0daeed3] {
126
+ .code-demo .code-area[data-v-e583bfde] {
127
127
  background: #fbfbfb;
128
128
  padding: 20px;
129
129
  border-top: 1px solid #eee;
130
130
  font-family: Consolas, Monaco, "Courier New", monospace;
131
131
  }
132
- .code-demo .code-area pre[data-v-e0daeed3],
133
- .code-demo .code-area code[data-v-e0daeed3] {
132
+ .code-demo .code-area pre[data-v-e583bfde],
133
+ .code-demo .code-area code[data-v-e583bfde] {
134
134
  margin: 0;
135
135
  font-size: 14px;
136
136
  line-height: 1.5;
@@ -138,4 +138,28 @@
138
138
  white-space: pre-wrap;
139
139
  word-break: break-all;
140
140
  line-height: 1.8;
141
- }
141
+ }
142
+ .tabs[data-v-fe4030ae] {
143
+ border: 1px solid #e4e7ed;
144
+ border-radius: 4px;
145
+ }
146
+ .tabs-header[data-v-fe4030ae] {
147
+ display: flex;
148
+ border-bottom: 1px solid #e4e7ed;
149
+ }
150
+ .tab-item[data-v-fe4030ae] {
151
+ padding: 10px 20px;
152
+ cursor: pointer;
153
+ border-bottom: 2px solid transparent;
154
+ }
155
+ .tab-item.active[data-v-fe4030ae] {
156
+ border-bottom-color: #409eff;
157
+ color: #409eff;
158
+ }
159
+ .tabs-content[data-v-fe4030ae] {
160
+ padding: 20px;
161
+ }
162
+
163
+ .tab-pane[data-v-3fe96054] {
164
+ /* 可自定义内容区样式 */
165
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikun2274/spiritechoui",
3
- "version": "0.1.51",
3
+ "version": "0.1.61",
4
4
  "main": "dist/spiritechoui.umd.cjs",
5
5
  "module": "dist/spiritechoui.es.js",
6
6
  "exports": {
package/readme.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # 我的第一个UI组件库 SpiritEchoUI
2
2
 
3
- ### 目前还是0.1.5版本
4
3
 
5
4
 
6
5
  ## 安装组件
@@ -24,11 +23,11 @@ npm uninstall @ikun2274/spiritechoui
24
23
  ```
25
24
  更新了代码块组件
26
25
  ```
27
-
26
+ ### 0.1.60 (2036-2-14 15:57)
27
+ ```
28
+ 更新了Tab&TabPane
29
+ ```
28
30
 
29
31
  ## 后续规划
30
32
 
31
33
 
32
- #### v0.2.x:新增表单组件(输入框、选择器等),完善按钮与表单的联动。
33
- #### v0.3.x:补充布局工具类,支持更灵活的响应式场景。
34
- #### v0.4.x:还不知道
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <div v-if="activeName === name" class="tab-pane">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ import { inject, onMounted } from 'vue';
9
+
10
+ export default {
11
+ name: 'TabPane',
12
+ props: {
13
+ name: {
14
+ type: String,
15
+ required: true
16
+ },
17
+ label: {
18
+ type: String,
19
+ required: true
20
+ }
21
+ },
22
+ setup(props) {
23
+ const TabsContext = inject('TabsContext');
24
+ const activeName = TabsContext.activeName;
25
+
26
+ // 挂载时注册到 Tabs
27
+ onMounted(() => {
28
+ TabsContext.addPane({
29
+ name: props.name,
30
+ label: props.label
31
+ });
32
+ });
33
+
34
+ return {
35
+ activeName
36
+ };
37
+ }
38
+ };
39
+ </script>
40
+
41
+ <style scoped>
42
+ .tab-pane {
43
+ /* 可自定义内容区样式 */
44
+ }
45
+ </style>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="tabs">
3
+ <div class="tabs-header">
4
+ <div
5
+ v-for="pane in panes"
6
+ :key="pane.name"
7
+ :class="['tab-item', { active: modelValue === pane.name }]"
8
+ @click="handleTabClick(pane.name)"
9
+ >
10
+ {{ pane.label }}
11
+ </div>
12
+ </div>
13
+ <div class="tabs-content">
14
+ <slot></slot>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+ import { ref, provide, computed } from 'vue';
21
+
22
+ export default {
23
+ name: 'Tabs',
24
+ props: {
25
+ modelValue: {
26
+ type: String,
27
+ required: true
28
+ }
29
+ },
30
+ emits: ['update:modelValue'],
31
+ setup(props, { emit }) {
32
+ const panes = ref([]);
33
+
34
+ // 提供给子组件的注册方法
35
+ const addPane = (pane) => {
36
+ panes.value.push(pane);
37
+ };
38
+
39
+ // 共享激活状态
40
+ const activeName = computed(() => props.modelValue);
41
+ provide('TabsContext', {
42
+ activeName,
43
+ addPane
44
+ });
45
+
46
+ // 点击切换标签
47
+ const handleTabClick = (name) => {
48
+ emit('update:modelValue', name);
49
+ };
50
+
51
+ return {
52
+ panes,
53
+ handleTabClick
54
+ };
55
+ }
56
+ };
57
+ </script>
58
+
59
+ <style scoped>
60
+ .tabs {
61
+ border: 1px solid #e4e7ed;
62
+ border-radius: 4px;
63
+ }
64
+ .tabs-header {
65
+ display: flex;
66
+ border-bottom: 1px solid #e4e7ed;
67
+ }
68
+ .tab-item {
69
+ padding: 10px 20px;
70
+ cursor: pointer;
71
+ border-bottom: 2px solid transparent;
72
+ }
73
+ .tab-item.active {
74
+ border-bottom-color: #409eff;
75
+ color: #409eff;
76
+ }
77
+ .tabs-content {
78
+ padding: 20px;
79
+ }
80
+ </style>
@@ -1,32 +1,40 @@
1
1
  // 组件库内部的 registerComponents.js 示例
2
2
  import MyUI from './MyUI';
3
3
  import ComponentInjector from './ComponentInjector';
4
-
5
4
  //引入组件
6
- import speButton from './components/Button.vue';
7
- import speinput from './components/SpInput.vue';
8
- import speblock from './components/SPEBlock.vue'
5
+ import speButton from './components/Basic/Button.vue';
6
+ import speinput from './components/form/SpInput.vue';
7
+ import speblock from './components/Tool/SPEBlock.vue'
9
8
 
10
- const injector = new ComponentInjector(MyUI);
11
9
 
12
- injector.register('form', 'speButton', speButton, {
10
+ import speTabs from './components/Navigation/Tabs.vue'
11
+ import speTabPane from './components/Navigation/TabPane.vue'
12
+
13
+ /////////////////
14
+ const injector = new ComponentInjector(MyUI);
15
+ injector.register('basic', 'speButton', speButton, {
13
16
  type: 'default',
14
17
  size: 'medium'
15
18
  });
16
- //假设有第二个组件
19
+
17
20
  injector.register('form', 'speinput', speinput);
18
21
  injector.register('tool', 'speblock', speblock);
19
-
20
22
  //Spirit EchoUI
23
+ injector.register('navigation', 'speTabs', speTabs);
24
+ injector.register('navigation', 'speTabPane', speTabPane);
25
+
26
+
21
27
 
22
- //全局激活组件
23
28
 
29
+
30
+ //全局激活组件
24
31
  MyUI.install = (app) => {
25
- app.component('SPE-Button', MyUI.form.speButton({}));
32
+ app.component('SPE-Button', MyUI.basic.speButton({}));
26
33
  app.component('SPE-Input', MyUI.form.speinput({}));
27
- app.component('SPE-Block', MyUI.tool.speblock({})
28
- );
34
+ app.component('SPE-Block', MyUI.tool.speblock({}));
29
35
 
36
+ app.component('SPE-Tabs', MyUI.navigation.speTabs({}));
37
+ app.component('SPE-TabPane', MyUI.navigation.speTabPane({}));
30
38
 
31
39
  };
32
40
 
@@ -1,10 +1,10 @@
1
1
  // src/types/global.d.ts
2
- import { SpInput } from "../components/SpInput.vue";
3
- import { Button } from "../components/Button.vue"; // 若有其他组件也需声明
2
+ import { SpInput } from "../components/form/SpInput.vue";
3
+ import { Button } from "../components/Basic/Button.vue"; // 若有其他组件也需声明
4
4
 
5
5
  declare module "vue" {
6
6
  export interface GlobalComponents {
7
7
  SpInput: typeof SpInput;
8
8
  Button: typeof Button;
9
9
  }
10
- }
10
+ }
@@ -0,0 +1,13 @@
1
+ // types.ts
2
+ export interface TabPaneProps {
3
+ name: string; // 唯一标识
4
+ label: string; // 标签文本
5
+ disabled?: boolean; // 是否禁用
6
+ }
7
+
8
+ export interface TabsProvide {
9
+ activeName: import("vue").ComputedRef<string>; // 当前激活的标签名
10
+ changeTab: (name: string) => void; // 切换标签方法
11
+ addPane: (pane: TabPaneProps) => void; // 注册子组件
12
+ removePane: (name: string) => void; // 注销子组件
13
+ }
File without changes