@schemx/vue 0.2.0 → 0.2.1

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.
package/dist/index.mjs CHANGED
@@ -1,34 +1,36 @@
1
1
  import "./style.css";
2
- import { computed, provide, onUnmounted, inject, shallowRef, ref, onMounted, watchEffect, onScopeDispose, defineComponent, createVNode, toRef, h, createTextVNode, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, createBlock, createSlots, withCtx, renderSlot, mergeProps } from "vue";
2
+ import { onScopeDispose, provide, inject, onUnmounted, shallowRef, computed, ref, onMounted, watchEffect, defineComponent, createVNode, h, toRef, createTextVNode, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, createBlock, createSlots, withCtx, renderSlot, mergeProps } from "vue";
3
3
  import classnames from "classnames";
4
4
  import { createRendererRegistry, createValidatorsRegistry, createForm, createField, createWatch, createEffect } from "@schemx/core";
5
5
  export * from "@schemx/core";
6
6
  import { omit } from "es-toolkit";
7
7
  const rendererRegistry = createRendererRegistry("input");
8
8
  const validatorRegistry = createValidatorsRegistry();
9
- const SCHEMX_INSTANCE_KEY = Symbol("SCHEMX_INSTANCE");
10
9
  function useForm(options = {}) {
11
- const { ...formOptions } = options;
12
10
  const mergedOptions = {
13
- ...formOptions,
14
- rendererRegistry: formOptions.rendererRegistry ?? rendererRegistry,
15
- validatorRegistry: formOptions.validatorRegistry ?? validatorRegistry
11
+ ...options,
12
+ rendererRegistry: options.rendererRegistry ?? rendererRegistry,
13
+ validatorRegistry: options.validatorRegistry ?? validatorRegistry
16
14
  };
17
- const instance = computed(() => createForm(mergedOptions));
18
- provide(SCHEMX_INSTANCE_KEY, instance.value);
19
- onUnmounted(() => {
20
- instance.value.destroy();
15
+ const instance = createForm(mergedOptions);
16
+ onScopeDispose(() => {
17
+ instance.destroy();
21
18
  });
22
- return instance.value;
19
+ return instance;
20
+ }
21
+ const SCHEMX_FORM_INSTANCE_KEY = Symbol("schemx:instance");
22
+ function createFormContext(instance) {
23
+ provide(SCHEMX_FORM_INSTANCE_KEY, instance);
23
24
  }
24
25
  function useFormContext() {
25
- const instance = inject(SCHEMX_INSTANCE_KEY);
26
+ const instance = inject(SCHEMX_FORM_INSTANCE_KEY, null);
26
27
  if (!instance) {
27
- throw new Error("useFormContext must be used within a Form");
28
+ throw new Error(
29
+ "[schemx] useFormContext() must be called inside a <SchemxForm> descendant. Ensure createFormContext(form) is called synchronously during setup()."
30
+ );
28
31
  }
29
32
  return instance;
30
33
  }
31
- const FIELD_CONTEXT_KEY = Symbol("schemx:field");
32
34
  const fieldHookCache = /* @__PURE__ */ new WeakMap();
33
35
  function createFieldHook(form, name) {
34
36
  const field = createField(form, name);
@@ -86,13 +88,18 @@ const useField = (name) => {
86
88
  });
87
89
  return activeEntry.result;
88
90
  };
91
+ const SCHEMX_FORM_FIELD_KEY = Symbol(
92
+ "schemx:field"
93
+ );
89
94
  function createFieldContext(field) {
90
- provide(FIELD_CONTEXT_KEY, field);
95
+ provide(SCHEMX_FORM_FIELD_KEY, field);
91
96
  }
92
97
  function useFieldContext() {
93
- const field = inject(FIELD_CONTEXT_KEY);
98
+ const field = inject(SCHEMX_FORM_FIELD_KEY);
94
99
  if (!field) {
95
- throw new Error("[schemx] useFieldContext() must be used inside a FormItem tree");
100
+ throw new Error(
101
+ "[schemx] useFieldContext() must be called inside a component tree where createFieldContext(field) has been called."
102
+ );
96
103
  }
97
104
  return field;
98
105
  }
@@ -208,14 +215,16 @@ const useDictionary = (options, fieldName) => {
208
215
  });
209
216
  return { list, loading, error, loadDict, refresh, mutate };
210
217
  };
211
- const FORM_CONTEXT_KEY = Symbol("FormContext");
212
- const createConfigContext = (props) => {
213
- provide(FORM_CONTEXT_KEY, props);
218
+ const SCHEMX_FORM_CONFIG_KEY = Symbol("schemx:form-config");
219
+ const createFormConfigContext = (props) => {
220
+ provide(SCHEMX_FORM_CONFIG_KEY, props);
214
221
  };
215
- function useConfigContext() {
216
- const context = inject(FORM_CONTEXT_KEY);
222
+ function useFormConfigContext() {
223
+ const context = inject(SCHEMX_FORM_CONFIG_KEY);
217
224
  if (!context) {
218
- throw new Error("useConfigContext must be used within a Form");
225
+ throw new Error(
226
+ "[schemx] useFormConfigContext() must be called inside a <SchemxForm> descendant. Ensure createFormConfigContext(props) is called synchronously during setup()."
227
+ );
219
228
  }
220
229
  return context;
221
230
  }
@@ -356,138 +365,163 @@ const FormGroup = /* @__PURE__ */ defineComponent((props, {
356
365
  }
357
366
  }
358
367
  });
359
- const FormItem = /* @__PURE__ */ defineComponent((props, {
360
- slots
361
- }) => {
362
- const schemaRef = toRef(props, "schema");
363
- if (isViewGroupSchema(schemaRef.value)) {
368
+ const FormItem = /* @__PURE__ */ defineComponent({
369
+ name: "SchemxItem",
370
+ props: {
371
+ schema: {
372
+ type: Object,
373
+ required: true
374
+ }
375
+ },
376
+ setup(props, {
377
+ slots
378
+ }) {
364
379
  return () => {
365
- return h(FormGroup, {
366
- schema: schemaRef.value
380
+ const schema = props.schema;
381
+ if (isViewGroupSchema(schema)) {
382
+ return h(FormGroup, {
383
+ schema
384
+ }, slots);
385
+ }
386
+ return h(FieldFormItem, {
387
+ schema
367
388
  }, slots);
368
389
  };
369
390
  }
370
- const form = useFormContext();
371
- const formContext = useConfigContext();
372
- const schema = () => schemaRef.value;
373
- const field = useField(schema().name);
374
- createFieldContext(field);
375
- const trigger = computed(() => mergeTrigger(schema().validationTrigger, formContext.validationTrigger, "onChange"));
376
- const canVerified = computed(() => {
377
- const isOperate = schema().visible && !schema().readonly && !schema().disabled;
378
- const rules = schema().rules;
379
- const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schema().rules;
380
- return isOperate && hasRules;
381
- });
382
- const handleChange = (v) => {
383
- var _a, _b;
384
- field.setValue(v);
385
- (_b = (_a = schema().componentProps) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a, v);
386
- if (canVerified.value && shouldValidateOn("change", trigger.value)) {
387
- field.validate();
388
- }
389
- };
390
- const handleBlur = () => {
391
- if (canVerified.value && shouldValidateOn("blur", trigger.value)) {
392
- field.validate();
393
- }
394
- };
395
- const componentProps = useStableRef(() => ({
396
- ...schema().componentProps,
397
- value: field.getValue(),
398
- onChange: handleChange,
399
- onBlur: handleBlur,
400
- "onUpdate:value": (v) => field.setValue(v)
401
- }));
402
- const renderRequired = () => {
403
- if (!schema().required || schema().disabled || schema().readonly) {
404
- return null;
405
- }
406
- return createVNode("span", {
407
- "class": "schemx-item__required"
408
- }, [createTextVNode("*")]);
409
- };
410
- const renderLabel = () => {
411
- const labelSlot = resolveSlot(slots, `${schema().name}Label`);
412
- if (labelSlot) {
413
- return labelSlot(schema());
414
- }
415
- const labelAlign = schema().labelAlign || formContext.labelAlign;
416
- const labelWidth = schema().labelWidth || formContext.labelWidth;
417
- const colon = schema().colon ?? formContext.colon;
418
- return createVNode("label", {
419
- "class": "schemx-item__label",
420
- "style": {
421
- width: labelWidth,
422
- textAlign: labelAlign
423
- }
424
- }, [renderRequired(), createVNode("span", {
425
- "class": "schemx-item__label-text"
426
- }, [schema().label, colon ? ":" : ""])]);
427
- };
428
- const renderContent = () => {
429
- const component = form.getRenderer(schema().componentType);
430
- if (!component) {
431
- throw new Error(`[schemx] Can not find component renderer of "${schema().componentType}".`);
432
- }
433
- const childSlots = extractChildSlots(normalizeNameKey(schema().name), slots);
434
- const columnElement = h(component, componentProps.value, childSlots);
435
- const contentSlot = resolveSlot(slots, `${schema().name}Content`);
436
- if (contentSlot) {
437
- return contentSlot({
438
- ...schema(),
439
- columnElement
440
- });
441
- }
442
- return createVNode("div", {
443
- "class": "schemx-item__control"
444
- }, [columnElement]);
445
- };
446
- const renderError = () => {
447
- const errorSlot = resolveSlot(slots, `${schema().name}Error`);
448
- if (errorSlot) {
449
- return errorSlot({
450
- ...schema(),
451
- errors: field.error.value
452
- });
453
- }
454
- if (!Array.isArray(field.error.value) || field.error.value.length === 0) {
455
- return null;
456
- }
457
- return createVNode("div", {
458
- "class": "schemx-item__error"
459
- }, [field.error.value[0]]);
460
- };
461
- return () => {
462
- if (!schema().visible) {
463
- return null;
464
- }
465
- const itemSlot = resolveSlot(slots, normalizeNameKey(schema().name));
466
- if (itemSlot) {
467
- return itemSlot(schema());
468
- }
469
- const labelPosition = schema().labelPosition || formContext.labelPosition;
470
- return createVNode("div", {
471
- "class": classnames("schemx-item-wrapper")
472
- }, [createVNode("div", {
473
- "class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schema().class, {
474
- "is-readonly": schema().readonly,
475
- "is-disabled": schema().disabled
476
- }),
477
- "style": {
478
- ...schema().style ?? {}
479
- }
480
- }, [renderLabel(), createVNode("div", {
481
- "class": "schemx-item__content"
482
- }, [renderContent(), renderError()])])]);
483
- };
484
- }, {
485
- name: "SchemxItem",
391
+ });
392
+ const FieldFormItem = /* @__PURE__ */ defineComponent({
393
+ name: "SchemxFieldItem",
486
394
  props: {
487
395
  schema: {
488
396
  type: Object,
489
397
  required: true
490
398
  }
399
+ },
400
+ setup(props, {
401
+ slots
402
+ }) {
403
+ const schemaRef = toRef(props, "schema");
404
+ const form = useFormContext();
405
+ const formContext = useFormConfigContext();
406
+ const schema = () => schemaRef.value;
407
+ const field = useField(schema().name);
408
+ createFieldContext(field);
409
+ const trigger = computed(() => mergeTrigger(schema().validationTrigger, formContext.validationTrigger, "onChange"));
410
+ const canVerified = computed(() => {
411
+ const isOperate = schema().visible && !schema().readonly && !schema().disabled;
412
+ const rules = schema().rules;
413
+ const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schema().rules;
414
+ return isOperate && hasRules;
415
+ });
416
+ const handleChange = (v) => {
417
+ var _a, _b;
418
+ field.setValue(v);
419
+ (_b = (_a = schema().componentProps) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a, v);
420
+ if (canVerified.value && shouldValidateOn("change", trigger.value)) {
421
+ field.validate();
422
+ }
423
+ };
424
+ const handleBlur = () => {
425
+ if (canVerified.value && shouldValidateOn("blur", trigger.value)) {
426
+ field.validate();
427
+ }
428
+ };
429
+ const componentProps = useStableRef(() => {
430
+ const currentSchema = schema();
431
+ return {
432
+ ...currentSchema.componentProps,
433
+ readonly: currentSchema.readonly,
434
+ disabled: currentSchema.disabled,
435
+ placeholder: currentSchema.placeholder,
436
+ formItemProps: currentSchema,
437
+ value: field.getValue(),
438
+ onChange: handleChange,
439
+ onBlur: handleBlur,
440
+ "onUpdate:value": (v) => field.setValue(v)
441
+ };
442
+ });
443
+ const renderRequired = () => {
444
+ if (!schema().required || schema().disabled || schema().readonly) {
445
+ return null;
446
+ }
447
+ return createVNode("span", {
448
+ "class": "schemx-item__required"
449
+ }, [createTextVNode("*")]);
450
+ };
451
+ const renderLabel = () => {
452
+ const labelSlot = resolveSlot(slots, `${schema().name}Label`);
453
+ if (labelSlot) {
454
+ return labelSlot(schema());
455
+ }
456
+ const labelAlign = schema().labelAlign || formContext.labelAlign;
457
+ const labelWidth = schema().labelWidth || formContext.labelWidth;
458
+ const colon = schema().colon ?? formContext.colon;
459
+ return createVNode("label", {
460
+ "class": "schemx-item__label",
461
+ "style": {
462
+ width: labelWidth,
463
+ textAlign: labelAlign
464
+ }
465
+ }, [renderRequired(), createVNode("span", {
466
+ "class": "schemx-item__label-text"
467
+ }, [schema().label, colon ? ":" : ""])]);
468
+ };
469
+ const renderContent = () => {
470
+ const component = form.getRenderer(schema().componentType);
471
+ if (!component) {
472
+ throw new Error(`[schemx] Can not find component renderer of "${schema().componentType}".`);
473
+ }
474
+ const childSlots = extractChildSlots(normalizeNameKey(schema().name), slots);
475
+ const columnElement = h(component, componentProps.value, childSlots);
476
+ const contentSlot = resolveSlot(slots, `${schema().name}Content`);
477
+ if (contentSlot) {
478
+ return contentSlot({
479
+ ...schema(),
480
+ columnElement
481
+ });
482
+ }
483
+ return createVNode("div", {
484
+ "class": "schemx-item__control"
485
+ }, [columnElement]);
486
+ };
487
+ const renderError = () => {
488
+ const errorSlot = resolveSlot(slots, `${schema().name}Error`);
489
+ if (errorSlot) {
490
+ return errorSlot({
491
+ ...schema(),
492
+ errors: field.error.value
493
+ });
494
+ }
495
+ if (!Array.isArray(field.error.value) || field.error.value.length === 0) {
496
+ return null;
497
+ }
498
+ return createVNode("div", {
499
+ "class": "schemx-item__error"
500
+ }, [field.error.value[0]]);
501
+ };
502
+ return () => {
503
+ if (!schema().visible) {
504
+ return null;
505
+ }
506
+ const itemSlot = resolveSlot(slots, normalizeNameKey(schema().name));
507
+ if (itemSlot) {
508
+ return itemSlot(schema());
509
+ }
510
+ const labelPosition = schema().labelPosition || formContext.labelPosition;
511
+ return createVNode("div", {
512
+ "class": classnames("schemx-item-wrapper")
513
+ }, [createVNode("div", {
514
+ "class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schema().class, {
515
+ "is-readonly": schema().readonly,
516
+ "is-disabled": schema().disabled
517
+ }),
518
+ "style": {
519
+ ...schema().style ?? {}
520
+ }
521
+ }, [renderLabel(), createVNode("div", {
522
+ "class": "schemx-item__content"
523
+ }, [renderContent(), renderError()])])]);
524
+ };
491
525
  }
492
526
  });
493
527
  const isViewGroupSchema = (schema) => {
@@ -568,7 +602,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
568
602
  setup(__props, { expose: __expose, emit: __emit }) {
569
603
  const props = __props;
570
604
  const emit = __emit;
571
- createConfigContext(
605
+ createFormConfigContext(
572
606
  omit(props, [
573
607
  "form",
574
608
  "modelValue",
@@ -607,6 +641,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
607
641
  (_a = props.onFieldsChange) == null ? void 0 : _a.call(props, changedPaths, allPaths);
608
642
  }
609
643
  });
644
+ createFormContext(form);
610
645
  watch(
611
646
  () => props.schemas,
612
647
  (schemas) => {
@@ -698,16 +733,21 @@ export {
698
733
  FormGroup,
699
734
  FormItem,
700
735
  WithRemoteOptions,
736
+ createFieldContext,
737
+ createFormConfigContext,
738
+ createFormContext,
701
739
  SchemxFormExport as default,
702
740
  rendererRegistry,
703
741
  SchemxFormExport as schemxForm,
704
- useConfigContext,
705
742
  useDictionary,
706
743
  useEffect,
707
744
  useField,
708
745
  useFieldContext,
709
746
  useForm,
747
+ useFormConfigContext,
710
748
  useFormContext,
749
+ useStableRef,
750
+ useViewSchemas,
711
751
  useWatch,
712
752
  useWatchAll,
713
753
  useWatchField,