Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
undefined-moe authored Nov 24, 2024
2 parents 2b61d81 + df1e53d commit 7fc02bf
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 25 deletions.
2 changes: 0 additions & 2 deletions packages/core/.npmignore

This file was deleted.

2 changes: 0 additions & 2 deletions packages/form/.npmignore

This file was deleted.

111 changes: 111 additions & 0 deletions packages/form/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# schemastery-vue

[![Codecov](https://img.shields.io/codecov/c/github/shigma/schemastery?style=flat-square)](https://codecov.io/gh/shigma/schemastery)
[![downloads](https://img.shields.io/npm/dm/schemastery-vue?style=flat-square)](https://www.npmjs.com/package/schemastery-vue)
[![npm](https://img.shields.io/npm/v/schemastery-vue?style=flat-square)](https://www.npmjs.com/package/schemastery-vue)
[![GitHub](https://img.shields.io/github/license/shigma/schemastery?style=flat-square)](https://github.com/shigma/schemastery/blob/master/LICENSE)

vue component for schemastery.

## Quick Start

This section describes how to use schemastery-vue in your project.

### Installation

```shell
npm i -D schemastery-vue element-plus vue-i18n markdown-vue @vueuse/core @maikolib/vite-plugin-yaml sass-embedded
# or
yarn add -D schemastery-vue element-plus vue-i18n markdown-vue @vueuse/core @maikolib/vite-plugin-yaml sass-embedded
```

### Usage

```ts
// main.ts
import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import form from "schemastery-vue";
import { createI18n } from "vue-i18n";
import Markdown from "markdown-vue";
import App from "./App.vue";

const i18n = createI18n({
legacy: false,
});
const app = createApp(App);

app.use(ElementPlus);
app.use(i18n);
app.use(form);
app.component("k-markdown", Markdown);
app.mount("#app");
```

```vue
<!-- App.vue -->
<template>
<k-form v-model="config" :schema="Config" :initial="initial"></k-form>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import Schema from "schemastery";
interface Config {
foo: boolean;
bar: string[];
}
const Config = Schema.object({
foo: Schema.boolean().default(false),
bar: Schema.array(Schema.string()).default([]),
});
const config = ref<Config>({
foo: false,
bar: ["foo"],
});
const initial = ref<Config>({
foo: false,
bar: ["foo"],
});
</script>
```

### Vite

```ts
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import yaml from "@maikolib/vite-plugin-yaml";

export default defineConfig({
// ...
plugins: [
// ...
vue(),
yaml(),
],
css: {
preprocessorOptions: {
scss: {
api: "modern-compiler",
},
},
},
});
```

## Projects Using This Package

Here are some repositories that are using this package:

1. [koishijs/docs](https://github.com/koishijs/docs/blob/main/.vitepress/theme/index.ts) - Documentation for Koishi.
2. [koishijs/webui](https://github.com/koishijs/webui/blob/main/packages/components/client/form/index.ts) - WebUI plugins for Koishi.
3. [DGCK81LNN/koishi-plugin-miniplug](https://github.com/DGCK81LNN/koishi-plugin-miniplug/blob/main/plugins/codemirror/client/components/codemirror.vue) - Code simple JavaScript plugins in your Koishi console
4. [initialencounter/chrome-extensions](https://github.com/initialencounter/chrome-extensions/blob/master/lims/src/options/src/main.ts) - Chrome-Extensions Pages

You can also refer to how they are used!
2 changes: 1 addition & 1 deletion packages/form/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "schemastery-vue",
"description": "Type driven schema validator",
"version": "7.3.4",
"version": "7.3.7",
"main": "src/index.ts",
"files": [
"src"
Expand Down
6 changes: 5 additions & 1 deletion packages/form/src/base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,15 @@ if (import.meta.hot) {
.k-schema-item {
p {
margin: 0;
margin: 0.25rem;
line-height: 1.7;
font-size: 0.875rem;
}
.markdown p {
margin: 0;
}
ul {
list-style: none;
width: 100%;
Expand Down
9 changes: 5 additions & 4 deletions packages/form/src/extensions/table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
></schema-primitive>
</td>

<td v-if="!disabled" class="button"
<td v-if="!disabled" class="k-schema-table-button"
:class="{ disabled: !i }"
@click.stop="up(i)"
@mouseenter="handleMouseEnter($event, null)"
Expand All @@ -76,7 +76,7 @@
<icon-arrow-up></icon-arrow-up>
</div>
</td>
<td v-if="!disabled" class="button"
<td v-if="!disabled" class="k-schema-table-button"
:class="{ disabled: i === entries.length - 1 }"
@click.stop="down(i)"
@mouseenter="handleMouseEnter($event, null)"
Expand All @@ -85,7 +85,7 @@
<icon-arrow-down></icon-arrow-down>
</div>
</td>
<td v-if="!disabled && !isFixedLength" class="button"
<td v-if="!disabled && !isFixedLength" class="k-schema-table-button"
:class="{ disabled: isMin }"
@click.stop="del(i)"
@mouseenter="handleMouseEnter($event, null)"
Expand Down Expand Up @@ -264,8 +264,9 @@ if (import.meta.hot) {
}
}
td.button {
td.k-schema-table-button {
width: 2rem;
max-width: 2rem;
color: var(--k-text-light);
cursor: pointer;
Expand Down
10 changes: 9 additions & 1 deletion packages/form/src/form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@

<script lang="ts" setup>
import { computed, PropType } from 'vue'
import { computed, inject, PropType, provide } from 'vue'
import { useI18n } from 'vue-i18n'
import { getChoices, Schema, useI18nText } from './utils'
import zhCN from './locales/zh-CN.yml'
import enUS from './locales/en-US.yml'
import type form from '.'
const props = defineProps({
schema: {} as PropType<Schema>,
initial: {},
modelValue: {},
disabled: Boolean,
showHeader: Boolean,
slots: { default: {} },
extensions: Array as PropType<form.Extension[]>,
})
const tt = useI18nText()
Expand Down Expand Up @@ -63,6 +66,11 @@ function hasTitle(schema: Schema): [isTitled: boolean, isEmpty: boolean] {
}
}
const extensions = inject<Set<form.Extension>>('__SCHEMASTERY_EXTENSIONS__')
provide('__SCHEMASTERY_EXTENSIONS__', new Set([...extensions, ...(props.extensions ?? [])]))
provide('__SCHEMASTERY_SLOTS__', props.slots)
const emit = defineEmits(['update:modelValue'])
const config = computed({
Expand Down
10 changes: 8 additions & 2 deletions packages/form/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { App, Component } from 'vue'
import extensions, { Schema, toColumns, useDisabled, useEntries, useModel } from './utils'
import { getFallback, Schema, toColumns, useDisabled, useEntries, useModel } from './utils'
import SchemaBase from './base.vue'
import Primitive from './primitive.vue'
import SchemaCheckbox from './extensions/checkbox.vue'
Expand All @@ -18,6 +18,8 @@ import KForm from './form.vue'

import './styles/index.scss'

const extensions = new Set<form.Extension>()

export * from 'cosmokit'

export { Primitive }
Expand All @@ -32,8 +34,10 @@ export const form = Object.assign(SchemaBase, {
useModel,
useEntries,
useDisabled,
getFallback,
extensions,
install(app: App) {
app.provide('__SCHEMASTERY_EXTENSIONS__', extensions)
app.component('k-form', KForm)
app.component('k-badge', KBadge)
app.component('k-schema', KSchema)
Expand All @@ -45,16 +49,18 @@ export const form = Object.assign(SchemaBase, {
useModel: typeof useModel
useEntries: typeof useEntries
useDisabled: typeof useDisabled
getFallback: typeof getFallback
extensions: Set<form.Extension>
install: (app: App) => void
}

export namespace form {
export interface Extension {
type: string
type?: string
role?: string
validate?: (value: any, schema: Schema) => boolean
component: Component
important?: boolean
}
}

Expand Down
18 changes: 13 additions & 5 deletions packages/form/src/schema.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
<span class="k-menu-icon"><icon-code></icon-code></span>
{{ t('edit.json') }}
</div>
<component
:is="slots.menu"
v-bind="{ schema, modelValue, initial, disabled }"
@update:modelValue="$emit('update:modelValue', $event)"
></component>
<div
class="k-menu-item"
:class="{ disabled: disabled || deepEqual(initial, modelValue) }"
Expand All @@ -37,7 +42,6 @@
<span class="k-menu-icon"><icon-reset></icon-reset></span>
{{ t('default') }}
</div>
<slot name="menu"></slot>
</template>
<template #desc>
<slot name="desc">
Expand Down Expand Up @@ -88,12 +92,13 @@

<script lang="ts" setup>
import { computed, PropType, ref, watch } from 'vue'
import { computed, inject, PropType, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { clone, deepEqual, isNullable } from 'cosmokit'
import { ElMessage } from 'element-plus'
import extensions, { getFallback, Schema, useI18nText } from './utils'
import { getFallback, Schema, useI18nText } from './utils'
import { IconCode, IconUndo, IconReset } from './icons'
import type form from '.'
import SchemaPrimitive from './primitive.vue'
import SchemaBase from './base.vue'
import zhCN from './locales/zh-CN.yml'
Expand All @@ -113,6 +118,9 @@ const props = defineProps({
prefix: { type: String, default: '' },
})
const extensions = inject<Set<form.Extension>>('__SCHEMASTERY_EXTENSIONS__')
const slots = inject<Record<string, Function>>('__SCHEMASTERY_SLOTS__')
const emit = defineEmits(['update:modelValue'])
const input = ref()
Expand Down Expand Up @@ -160,10 +168,10 @@ const SchemaComponent = computed(() => {
if (ext.type && props.schema?.type !== ext.type) return
if (ext.role && props.schema?.meta.role !== ext.role) return
if (ext.validate) {
const valid = isNullable(props.modelValue) || ext.validate(props.modelValue, props.schema)
const valid = isNullable(props.modelValue) && !ext.important || ext.validate(props.modelValue, props.schema)
if (!valid) return
}
return [ext.component, +!!ext.type + +!!ext.role] as const
return [ext.component, +!!ext.type + +!!ext.role + (ext.important ? Infinity : 0)] as const
}).filter(Boolean).sort((a, b) => b[1] - a[1])
candidates.push([SchemaBase, 0])
return candidates[0][0]
Expand Down
8 changes: 4 additions & 4 deletions packages/form/src/styles/index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import './menu.scss';
@use './menu.scss';

.k-schema-item {
position: relative;
Expand Down Expand Up @@ -51,17 +51,17 @@

&-cell-input {
min-width: 6rem;
width: 10rem;
// width: 10rem;
}

&-cell-input-number {
min-width: 6rem;
width: 10rem;
// width: 10rem;
}

&-cell-select {
min-width: 6rem;
width: 10rem;
// width: 10rem;
}

.el-input__wrapper {
Expand Down
3 changes: 0 additions & 3 deletions packages/form/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import form from '.'

export { Schema }

const extensions = new Set<form.Extension>()
export default extensions

export function useI18nText() {
const composer = useI18n()
const context: any = {}
Expand Down

0 comments on commit 7fc02bf

Please sign in to comment.