slexkit 0.3.0 → 0.3.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +4 -3
  3. package/README.zh-CN.md +4 -3
  4. package/dist/ai/llms-components.txt +2 -1
  5. package/dist/ai/llms-full.txt +73 -42
  6. package/dist/ai/llms-runtime.txt +11 -12
  7. package/dist/ai/llms.txt +1 -1
  8. package/dist/ai/slexkit-ai-manifest.json +77 -73
  9. package/dist/components/checkbox.js +1 -0
  10. package/dist/components/choice.css +2 -2
  11. package/dist/components/display.css +1 -1
  12. package/dist/components/index.js +56 -153
  13. package/dist/components/input.css +53 -119
  14. package/dist/components/input.js +33 -143
  15. package/dist/components/radio-group.js +1 -0
  16. package/dist/components/select.css +0 -6
  17. package/dist/components/slider.css +27 -18
  18. package/dist/components/specs.js +2 -1
  19. package/dist/components/switch.css +3 -3
  20. package/dist/components/switch.js +1 -0
  21. package/dist/components/text-input.css +21 -90
  22. package/dist/components/text.js +12 -0
  23. package/dist/components/tooling.css +0 -1
  24. package/dist/runtime.cjs +22 -5
  25. package/dist/runtime.js +22 -5
  26. package/dist/slexkit.cjs +78 -158
  27. package/dist/slexkit.css +54 -121
  28. package/dist/slexkit.js +78 -158
  29. package/dist/types/version.d.ts +2 -2
  30. package/dist/umd/slexkit.tooling.umd.js +77 -158
  31. package/dist/umd/slexkit.umd.js +78 -158
  32. package/package.json +3 -2
  33. package/skills/slexkit-host-integration/SKILL.md +1 -1
  34. package/src/components/svelte/display/Text.svelte +14 -1
  35. package/src/components/svelte/input/Checkbox.svelte +1 -1
  36. package/src/components/svelte/input/Input.svelte +0 -110
  37. package/src/components/svelte/input/RadioGroup.svelte +1 -1
  38. package/src/components/svelte/input/Switch.svelte +1 -1
  39. package/src/styles/components/choice.css +2 -2
  40. package/src/styles/components/select.css +0 -6
  41. package/src/styles/components/slider.css +27 -18
  42. package/src/styles/components/switch.css +3 -3
  43. package/src/styles/components/text-input.css +21 -90
  44. package/src/styles/display.css +1 -1
  45. package/src/styles/tooling.css +0 -1
@@ -792,6 +792,9 @@
792
792
  const mode = getComponentStateMode(type);
793
793
  return mode === "value" || mode === "checked" || mode === "enabled";
794
794
  }
795
+ function isReadableComponent(type) {
796
+ return getComponentStateMode(type) === "readable";
797
+ }
795
798
  function isStatefulComponent(type) {
796
799
  return getComponentStateMode(type) !== "none";
797
800
  }
@@ -908,7 +911,10 @@
908
911
  function ensureComponentState(name, type, components, componentTypes) {
909
912
  if (!components[name])
910
913
  components[name] = {};
911
- componentTypes[name] = type;
914
+ const previousType = componentTypes[name] ?? "";
915
+ if (!(isWritableComponent(previousType) && isReadableComponent(type))) {
916
+ componentTypes[name] = type;
917
+ }
912
918
  return components[name];
913
919
  }
914
920
  function syncReadableComponentProp(type, state, propName, value) {
@@ -936,6 +942,9 @@
936
942
  function syncComponentProps(type, name, props, components, componentTypes) {
937
943
  if (!name || !isStatefulComponent(type))
938
944
  return;
945
+ const previousType = componentTypes[name] ?? "";
946
+ if (isWritableComponent(previousType) && isReadableComponent(type))
947
+ return;
939
948
  const state = ensureComponentState(name, type, components, componentTypes);
940
949
  if (type === "input" && typeof props.type === "string") {
941
950
  assignInputType(state, props.type);
@@ -1000,7 +1009,7 @@
1000
1009
  function warnDuplicateState(ns, name, currentType, currentPath, previous) {
1001
1010
  console.warn(`[SlexKit][${ns}] Component state '${name}' is declared more than once at ${previous.path} and ${currentPath}; state is shared by namespace and component name.`);
1002
1011
  if (previous.type !== currentType) {
1003
- console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType}); the latest rendered type controls write behavior.`);
1012
+ console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType}); use distinct names when components should not share state.`);
1004
1013
  }
1005
1014
  }
1006
1015
  function dynamicStateBinding(type, props) {
@@ -1012,6 +1021,9 @@
1012
1021
  return previousType === "input" && currentType === "slider" || previousType === "slider" && currentType === "input";
1013
1022
  }
1014
1023
  function shouldWarnDuplicateState(currentType, currentBinding, previous) {
1024
+ if (isReadableComponent(previous.type) && isReadableComponent(currentType)) {
1025
+ return false;
1026
+ }
1015
1027
  if (currentBinding && previous.stateBinding === currentBinding && isMirroredValueControlPair(previous.type, currentType)) {
1016
1028
  return false;
1017
1029
  }
@@ -1822,7 +1834,7 @@ ${parseSource}
1822
1834
  var parseSlexKitDsl = parseSlexSource;
1823
1835
 
1824
1836
  // src/version.ts
1825
- var SLEXKIT_VERSION = "0.3.0";
1837
+ var SLEXKIT_VERSION = "0.3.1";
1826
1838
  var SLEX_PROTOCOL_VERSION = "0.1";
1827
1839
  var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
1828
1840
  function getSlexKitInfo() {
@@ -2950,7 +2962,6 @@ ${parseSource}
2950
2962
  min: { type: "string | number", dynamic: true, description: "Minimum value used by numeric input controls." },
2951
2963
  max: { type: "string | number", dynamic: true, description: "Maximum value used by numeric input controls." },
2952
2964
  step: { type: "string | number", dynamic: true, description: "Step size used by numeric input controls." },
2953
- controls: { type: "boolean", default: true, dynamic: true, description: "Show decrement and increment buttons for numeric inputs." },
2954
2965
  onchange: { type: "write-expression", description: "Write expression invoked when the value changes." }
2955
2966
  },
2956
2967
  children: noChildren,
@@ -3458,6 +3469,8 @@ ${parseSource}
3458
3469
  content: { type: "string", dynamic: true, description: "Alias for text." },
3459
3470
  label: { type: "string", dynamic: true, description: "Alias for text." },
3460
3471
  variant: { type: "string", values: ["default", "muted"], default: "default", description: "Text visual variant." },
3472
+ color: { type: "string", dynamic: true, description: "Optional CSS color for controlled previews." },
3473
+ size: { type: "string | number", dynamic: true, description: "Optional font size. Numbers are treated as px." },
3461
3474
  class: { type: "string", description: "Additional host-controlled CSS class." }
3462
3475
  },
3463
3476
  children: noChildren,
@@ -3828,7 +3841,11 @@ ${parseSource}
3828
3841
  return Object.keys(value).some((key) => key.includes(":"));
3829
3842
  }
3830
3843
  function bareLayoutFromSource(value) {
3831
- const { slex: _slex, namespace: _namespace, g: _g, layout: _layout, ...layout } = value;
3844
+ const layout = { ...value };
3845
+ delete layout.slex;
3846
+ delete layout.namespace;
3847
+ delete layout.g;
3848
+ delete layout.layout;
3832
3849
  return layout;
3833
3850
  }
3834
3851
  function isStateOnlySource(value) {
@@ -12599,6 +12616,7 @@ ${component_stack}
12599
12616
  reset(label2);
12600
12617
  reset(span);
12601
12618
  template_effect(($0, $1) => {
12619
+ set_attribute2(label2, "data-disabled", get2(p).disabled ? "true" : undefined);
12602
12620
  input.disabled = !!get2(p).disabled;
12603
12621
  set_attribute2(input, "data-state", get2(checked) ? "checked" : "unchecked");
12604
12622
  set_attribute2(input, "aria-label", $0);
@@ -12674,6 +12692,7 @@ ${component_stack}
12674
12692
  reset(span);
12675
12693
  template_effect(($0, $1) => {
12676
12694
  set_attribute2(label2, "data-state", get2(enabled) ? "on" : "off");
12695
+ set_attribute2(label2, "data-disabled", get2(p).disabled ? "true" : undefined);
12677
12696
  input.disabled = !!get2(p).disabled;
12678
12697
  set_attribute2(input, "aria-label", $0);
12679
12698
  set_text(text_1, $1);
@@ -12694,26 +12713,11 @@ ${component_stack}
12694
12713
  var nextInputId = 0;
12695
12714
  var root_14 = from_html(`<label class="slex-input-label"> </label>`);
12696
12715
  var root_2 = from_html(`<span class="slex-input-unit" aria-hidden="true"> </span>`);
12697
- var root_33 = from_html(`<span class="slex-input-controls"><button class="slex-input-step" type="button">+</button> <button class="slex-input-step" type="button">-</button></span>`);
12698
- var root_4 = from_html(`<div class="slex-input-description"> </div>`);
12699
- var root_52 = from_html(`<div class="slex-input-error" role="alert"> </div>`);
12700
- var root8 = from_html(`<div class="slex-input-field"><!> <div class="slex-input-control"><input class="slex-input"/> <!> <!></div> <!> <!></div>`);
12716
+ var root_33 = from_html(`<div class="slex-input-description"> </div>`);
12717
+ var root_4 = from_html(`<div class="slex-input-error" role="alert"> </div>`);
12718
+ var root8 = from_html(`<div class="slex-input-field"><!> <div class="slex-input-control"><input class="slex-input"/> <!></div> <!> <!></div>`);
12701
12719
  function Input($$anchor, $$props) {
12702
12720
  push($$props, true);
12703
- const engineeringPrefixFactors = {
12704
- p: 0.000000000001,
12705
- n: 0.000000001,
12706
- u: 0.000001,
12707
- "µ": 0.000001,
12708
- "碌": 0.000001,
12709
- m: 0.001,
12710
- k: 1000,
12711
- K: 1000,
12712
- M: 1e6,
12713
- meg: 1e6,
12714
- G: 1e9,
12715
- T: 1000000000000
12716
- };
12717
12721
  let p = state(proxy({}));
12718
12722
  let value = state("");
12719
12723
  const fallbackId = `slex-input-${++nextInputId}`;
@@ -12725,8 +12729,6 @@ ${component_stack}
12725
12729
  const readonly = user_derived(() => bool(get2(p).readonly) || bool(get2(p).readOnly));
12726
12730
  const required = user_derived(() => bool(get2(p).required));
12727
12731
  const invalid2 = user_derived(() => bool(get2(p).invalid) || !!get2(errorText));
12728
- const steppable = user_derived(isSteppableInput);
12729
- const controls = user_derived(() => get2(steppable) && get2(p).controls !== false && get2(p).controls !== "false");
12730
12732
  const componentId = user_derived(() => safeId($$props.componentName));
12731
12733
  const inputId = user_derived(() => text2(get2(p).id) || (get2(componentId) ? `slex-input-${get2(componentId)}` : fallbackId));
12732
12734
  const descriptionId = user_derived(() => `${get2(inputId)}-description`);
@@ -12737,10 +12739,6 @@ ${component_stack}
12737
12739
  get2(descriptionText) ? get2(descriptionId) : "",
12738
12740
  get2(errorText) ? get2(errorId) : ""
12739
12741
  ].filter(Boolean).join(" "));
12740
- const numericValue = user_derived(readNumericValue);
12741
- const controlLabel = user_derived(() => get2(labelText) || text2(get2(p).placeholder) || $$props.componentName || "input");
12742
- const decrementDisabled = user_derived(() => !canStep(-1));
12743
- const incrementDisabled = user_derived(() => !canStep(1));
12744
12742
  user_effect(() => bindPropStore($$props.props, (next2) => {
12745
12743
  set(p, next2, true);
12746
12744
  set(value, text2(next2.value), true);
@@ -12751,72 +12749,6 @@ ${component_stack}
12751
12749
  function inputType() {
12752
12750
  return text2(get2(p).type, "text") === "engineering" ? "text" : text2(get2(p).type, "text");
12753
12751
  }
12754
- function isSteppableInput() {
12755
- const kind = text2(get2(p).type, "text");
12756
- return kind === "number" || kind === "engineering" || get2(p).min !== undefined || get2(p).max !== undefined || get2(p).step !== undefined;
12757
- }
12758
- function numericProp(input) {
12759
- if (input === undefined || input === null || input === "")
12760
- return;
12761
- const next2 = Number(input);
12762
- return Number.isFinite(next2) ? next2 : undefined;
12763
- }
12764
- function stepSize() {
12765
- const next2 = numericProp(get2(p).step);
12766
- if (next2 !== undefined && next2 > 0)
12767
- return next2;
12768
- if (text2(get2(p).type, "text") !== "engineering")
12769
- return 1;
12770
- const parsed = parseEngineeringNumber(get2(value));
12771
- if (!parsed.valid || !parsed.prefix)
12772
- return 1;
12773
- return engineeringPrefixFactors[parsed.prefix] ?? 1;
12774
- }
12775
- function readNumericValue() {
12776
- if (text2(get2(p).type, "text") === "engineering") {
12777
- const parsed = parseEngineeringNumber(get2(value));
12778
- return parsed.valid && parsed.number !== null ? parsed.number : null;
12779
- }
12780
- const next2 = Number(get2(value));
12781
- return Number.isFinite(next2) ? next2 : null;
12782
- }
12783
- function clamp(next2) {
12784
- const min = numericProp(get2(p).min);
12785
- const max = numericProp(get2(p).max);
12786
- let clamped = next2;
12787
- if (min !== undefined)
12788
- clamped = Math.max(min, clamped);
12789
- if (max !== undefined)
12790
- clamped = Math.min(max, clamped);
12791
- return clamped;
12792
- }
12793
- function canStep(direction) {
12794
- if (!get2(controls) || get2(disabled) || get2(readonly) || get2(numericValue) === null)
12795
- return false;
12796
- return clamp(get2(numericValue) + direction * stepSize()) !== get2(numericValue);
12797
- }
12798
- function formatSteppedValue(next2) {
12799
- if (text2(get2(p).type, "text") !== "engineering")
12800
- return text2(next2);
12801
- const parsed = parseEngineeringNumber(get2(value));
12802
- if (!parsed.valid)
12803
- return text2(next2);
12804
- const factor = parsed.prefix ? engineeringPrefixFactors[parsed.prefix] : undefined;
12805
- const visibleNumber = factor ? next2 / factor : next2;
12806
- return `${formatNumber2(visibleNumber)}${parsed.prefix}${parsed.unit}`;
12807
- }
12808
- function formatNumber2(next2) {
12809
- return text2(Number(next2.toPrecision(12)));
12810
- }
12811
- function emitValue(nextValue) {
12812
- set(value, nextValue, true);
12813
- emit($$props.ctx, "change", text2(get2(p).type, "text") === "engineering" ? parseEngineeringNumber(get2(value)) : get2(value));
12814
- }
12815
- function stepBy(direction) {
12816
- if (!canStep(direction) || get2(numericValue) === null)
12817
- return;
12818
- emitValue(formatSteppedValue(clamp(get2(numericValue) + direction * stepSize())));
12819
- }
12820
12752
  function update2(event2) {
12821
12753
  if (get2(disabled) || get2(readonly))
12822
12754
  return;
@@ -12842,9 +12774,9 @@ ${component_stack}
12842
12774
  });
12843
12775
  }
12844
12776
  var div_1 = sibling(node, 2);
12845
- var input_1 = child(div_1);
12846
- remove_input_defaults(input_1);
12847
- var node_1 = sibling(input_1, 2);
12777
+ var input = child(div_1);
12778
+ remove_input_defaults(input);
12779
+ var node_1 = sibling(input, 2);
12848
12780
  {
12849
12781
  var consequent_1 = ($$anchor2) => {
12850
12782
  var span = root_2();
@@ -12858,33 +12790,11 @@ ${component_stack}
12858
12790
  $$render(consequent_1);
12859
12791
  });
12860
12792
  }
12861
- var node_2 = sibling(node_1, 2);
12862
- {
12863
- var consequent_2 = ($$anchor2) => {
12864
- var span_1 = root_33();
12865
- var button = child(span_1);
12866
- var button_1 = sibling(button, 2);
12867
- reset(span_1);
12868
- template_effect(() => {
12869
- set_attribute2(button, "aria-label", `Increase ${get2(controlLabel)}`);
12870
- button.disabled = get2(incrementDisabled);
12871
- set_attribute2(button_1, "aria-label", `Decrease ${get2(controlLabel)}`);
12872
- button_1.disabled = get2(decrementDisabled);
12873
- });
12874
- delegated("click", button, () => stepBy(1));
12875
- delegated("click", button_1, () => stepBy(-1));
12876
- append($$anchor2, span_1);
12877
- };
12878
- if_block(node_2, ($$render) => {
12879
- if (get2(controls))
12880
- $$render(consequent_2);
12881
- });
12882
- }
12883
12793
  reset(div_1);
12884
- var node_3 = sibling(div_1, 2);
12794
+ var node_2 = sibling(div_1, 2);
12885
12795
  {
12886
- var consequent_3 = ($$anchor2) => {
12887
- var div_2 = root_4();
12796
+ var consequent_2 = ($$anchor2) => {
12797
+ var div_2 = root_33();
12888
12798
  var text_3 = child(div_2, true);
12889
12799
  reset(div_2);
12890
12800
  template_effect(() => {
@@ -12893,15 +12803,15 @@ ${component_stack}
12893
12803
  });
12894
12804
  append($$anchor2, div_2);
12895
12805
  };
12896
- if_block(node_3, ($$render) => {
12806
+ if_block(node_2, ($$render) => {
12897
12807
  if (get2(descriptionText))
12898
- $$render(consequent_3);
12808
+ $$render(consequent_2);
12899
12809
  });
12900
12810
  }
12901
- var node_4 = sibling(node_3, 2);
12811
+ var node_3 = sibling(node_2, 2);
12902
12812
  {
12903
- var consequent_4 = ($$anchor2) => {
12904
- var div_3 = root_52();
12813
+ var consequent_3 = ($$anchor2) => {
12814
+ var div_3 = root_4();
12905
12815
  var text_4 = child(div_3, true);
12906
12816
  reset(div_3);
12907
12817
  template_effect(() => {
@@ -12910,9 +12820,9 @@ ${component_stack}
12910
12820
  });
12911
12821
  append($$anchor2, div_3);
12912
12822
  };
12913
- if_block(node_4, ($$render) => {
12823
+ if_block(node_3, ($$render) => {
12914
12824
  if (get2(errorText))
12915
- $$render(consequent_4);
12825
+ $$render(consequent_3);
12916
12826
  });
12917
12827
  }
12918
12828
  reset(div);
@@ -12921,21 +12831,20 @@ ${component_stack}
12921
12831
  set_attribute2(div, "data-required", get2(required) ? "true" : undefined);
12922
12832
  set_attribute2(div, "data-readonly", get2(readonly) ? "true" : undefined);
12923
12833
  set_attribute2(div_1, "data-has-unit", get2(unitText) ? "true" : undefined);
12924
- set_attribute2(div_1, "data-has-controls", get2(controls) ? "true" : undefined);
12925
- set_attribute2(input_1, "id", get2(inputId));
12926
- set_attribute2(input_1, "type", $0);
12927
- set_attribute2(input_1, "inputmode", $1);
12928
- set_attribute2(input_1, "name", $2);
12929
- set_attribute2(input_1, "placeholder", $3);
12930
- input_1.disabled = get2(disabled);
12931
- input_1.readOnly = get2(readonly);
12932
- input_1.required = get2(required);
12933
- set_attribute2(input_1, "min", $4);
12934
- set_attribute2(input_1, "max", $5);
12935
- set_attribute2(input_1, "step", $6);
12936
- set_attribute2(input_1, "aria-label", get2(computedAriaLabel) || undefined);
12937
- set_attribute2(input_1, "aria-describedby", get2(describedBy) || undefined);
12938
- set_attribute2(input_1, "aria-invalid", get2(invalid2) ? "true" : undefined);
12834
+ set_attribute2(input, "id", get2(inputId));
12835
+ set_attribute2(input, "type", $0);
12836
+ set_attribute2(input, "inputmode", $1);
12837
+ set_attribute2(input, "name", $2);
12838
+ set_attribute2(input, "placeholder", $3);
12839
+ input.disabled = get2(disabled);
12840
+ input.readOnly = get2(readonly);
12841
+ input.required = get2(required);
12842
+ set_attribute2(input, "min", $4);
12843
+ set_attribute2(input, "max", $5);
12844
+ set_attribute2(input, "step", $6);
12845
+ set_attribute2(input, "aria-label", get2(computedAriaLabel) || undefined);
12846
+ set_attribute2(input, "aria-describedby", get2(describedBy) || undefined);
12847
+ set_attribute2(input, "aria-invalid", get2(invalid2) ? "true" : undefined);
12939
12848
  }, [
12940
12849
  () => inputType(),
12941
12850
  () => text2(get2(p).type, "text") === "engineering" ? "decimal" : undefined,
@@ -12945,12 +12854,12 @@ ${component_stack}
12945
12854
  () => get2(p).max === undefined ? undefined : text2(get2(p).max),
12946
12855
  () => get2(p).step === undefined ? undefined : text2(get2(p).step)
12947
12856
  ]);
12948
- delegated("input", input_1, update2);
12949
- bind_value(input_1, () => get2(value), ($$value) => set(value, $$value));
12857
+ delegated("input", input, update2);
12858
+ bind_value(input, () => get2(value), ($$value) => set(value, $$value));
12950
12859
  append($$anchor, div);
12951
12860
  pop();
12952
12861
  }
12953
- delegate(["input", "click"]);
12862
+ delegate(["input"]);
12954
12863
 
12955
12864
  // src/components/svelte/input/RadioGroup.svelte
12956
12865
  var root_34 = from_html(`<span> </span>`);
@@ -13066,6 +12975,7 @@ ${component_stack}
13066
12975
  reset(label2);
13067
12976
  reset(span_1);
13068
12977
  template_effect(($0, $1, $2) => {
12978
+ set_attribute2(label2, "data-disabled", get2(disabled) ? "true" : undefined);
13069
12979
  set_attribute2(input, "name", $0);
13070
12980
  set_value(input, $1);
13071
12981
  set_checked(input, get2(itemValue) === get2(value));
@@ -13101,7 +13011,7 @@ ${component_stack}
13101
13011
  var root_16 = from_html(`<label class="slex-select-label"><!> <!></label>`);
13102
13012
  var root_8 = from_html(`<span class="slex-select-check" aria-hidden="true"></span>`);
13103
13013
  var root_6 = from_html(`<li role="option"><span class="slex-select-option-label"><!> <span> </span></span> <!></li>`);
13104
- var root_53 = from_html(`<ul class="slex-select-menu" role="listbox"></ul>`);
13014
+ var root_52 = from_html(`<ul class="slex-select-menu" role="listbox"></ul>`);
13105
13015
  var root_9 = from_html(`<option> </option>`);
13106
13016
  var root10 = from_html(`<div class="slex-select"><!> <button type="button" class="slex-select-trigger" aria-haspopup="listbox"><span class="slex-select-value"><!> <span> </span></span> <span class="slex-select-icon" aria-hidden="true"></span></button> <!> <select class="slex-select-native" tabindex="-1" aria-hidden="true"><option> </option><!></select></div>`);
13107
13017
  function Select($$anchor, $$props) {
@@ -13305,7 +13215,7 @@ ${component_stack}
13305
13215
  var node_4 = sibling(button, 2);
13306
13216
  {
13307
13217
  var consequent_6 = ($$anchor2) => {
13308
- var ul = root_53();
13218
+ var ul = root_52();
13309
13219
  each(ul, 21, () => get2(options), index, ($$anchor3, item, index2) => {
13310
13220
  const isSelected = user_derived(() => get2(item).value === text2(get2(value)));
13311
13221
  const isActive = user_derived(() => index2 === get2(activeIndex));
@@ -16156,7 +16066,7 @@ Migration example: ${hintLines.join(" ")}`;
16156
16066
  delegate(["click"]);
16157
16067
 
16158
16068
  // src/components/svelte/input/Tabs.svelte
16159
- var root_54 = from_html(`<span class="slex-sr-only"> </span>`);
16069
+ var root_53 = from_html(`<span class="slex-sr-only"> </span>`);
16160
16070
  var root_36 = from_html(`<!> <!>`, 1);
16161
16071
  var root_82 = from_html(`<div></div>`);
16162
16072
  var root_18 = from_html(`<!> <span class="slex-tabs-selected-indicator" aria-hidden="true"></span>`, 1);
@@ -16334,7 +16244,7 @@ Migration example: ${hintLines.join(" ")}`;
16334
16244
  var node_4 = sibling(node_3, 2);
16335
16245
  {
16336
16246
  var consequent_1 = ($$anchor5) => {
16337
- var span = root_54();
16247
+ var span = root_53();
16338
16248
  var text_1 = child(span, true);
16339
16249
  reset(span);
16340
16250
  template_effect(() => set_text(text_1, get2(label2)));
@@ -16774,7 +16684,7 @@ Migration example: ${hintLines.join(" ")}`;
16774
16684
  var root_111 = from_html(`<button><!> <!></button>`);
16775
16685
  var root_62 = from_html(`<span class="sr-only"> </span>`);
16776
16686
  var root_83 = from_svg(`<svg fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>`);
16777
- var root_55 = from_html(`<a><!> <!></a>`);
16687
+ var root_54 = from_html(`<a><!> <!></a>`);
16778
16688
  function CloseButton($$anchor, $$props) {
16779
16689
  push($$props, true);
16780
16690
  let color = prop($$props, "color", 3, "gray"), name = prop($$props, "name", 3, "Close"), size = prop($$props, "size", 3, "md"), restProps = rest_props($$props, [
@@ -16848,7 +16758,7 @@ Migration example: ${hintLines.join(" ")}`;
16848
16758
  append($$anchor2, button);
16849
16759
  };
16850
16760
  var alternate_2 = ($$anchor2) => {
16851
- var a = root_55();
16761
+ var a = root_54();
16852
16762
  attribute_effect(a, ($0) => ({
16853
16763
  ...restProps,
16854
16764
  onclick,
@@ -17481,11 +17391,21 @@ Migration example: ${hintLines.join(" ")}`;
17481
17391
  push($$props, true);
17482
17392
  let p = state(proxy({}));
17483
17393
  user_effect(() => bindPropStore($$props.props, (next2) => set(p, next2, true)));
17394
+ const color = user_derived(() => get2(p).color == null || get2(p).color === "" ? undefined : text2(get2(p).color));
17395
+ const size = user_derived(() => cssLength(get2(p).size));
17396
+ function cssLength(value) {
17397
+ if (value == null || value === "")
17398
+ return;
17399
+ const rendered = text2(value);
17400
+ return /^-?\d+(\.\d+)?$/.test(rendered) ? `${rendered}px` : rendered;
17401
+ }
17484
17402
  var div = root20();
17403
+ let styles;
17485
17404
  var text_1 = child(div, true);
17486
17405
  reset(div);
17487
17406
  template_effect(($0, $1) => {
17488
17407
  set_class(div, 1, $0);
17408
+ styles = set_style(div, "", styles, { color: get2(color), "font-size": get2(size) });
17489
17409
  set_text(text_1, $1);
17490
17410
  }, [
17491
17411
  () => `slex-text${get2(p).variant ? ` slex-text--${text2(get2(p).variant)}` : ""}${get2(p).class ? ` ${text2(get2(p).class)}` : ""}`,
@@ -17657,7 +17577,7 @@ Migration example: ${hintLines.join(" ")}`;
17657
17577
  var root_45 = from_html(`<span class="slex-code-block-language"> </span>`);
17658
17578
  var root_114 = from_html(`<figcaption class="slex-code-block-header"><span class="slex-code-block-title"><!> <!></span> <!></figcaption>`);
17659
17579
  var root_72 = from_html(`<span> </span>`);
17660
- var root_56 = from_html(`<span class="slex-code-line"><span class="slex-code-line-content"></span></span>`);
17580
+ var root_55 = from_html(`<span class="slex-code-line"><span class="slex-code-line-content"></span></span>`);
17661
17581
  var root22 = from_html(`<figure class="slex-code-block"><!> <pre class="slex-code-block-pre"><code></code></pre></figure>`);
17662
17582
  function CodeBlock($$anchor, $$props) {
17663
17583
  push($$props, true);
@@ -17826,7 +17746,7 @@ Migration example: ${hintLines.join(" ")}`;
17826
17746
  var pre = sibling(node, 2);
17827
17747
  var code_1 = child(pre);
17828
17748
  each(code_1, 21, () => get2(lines), index, ($$anchor2, line) => {
17829
- var span_3 = root_56();
17749
+ var span_3 = root_55();
17830
17750
  var span_4 = child(span_3);
17831
17751
  each(span_4, 21, () => get2(line), index, ($$anchor3, token) => {
17832
17752
  var fragment_1 = comment();
@@ -31966,7 +31886,7 @@ l0,-` + (midHeight + 144) + `c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949
31966
31886
 
31967
31887
  // src/components/svelte/content/Section.svelte
31968
31888
  var root_28 = from_html(`<div class="slex-section-eyebrow"> </div>`);
31969
- var root_57 = from_html(`<span> </span>`);
31889
+ var root_56 = from_html(`<span> </span>`);
31970
31890
  var root_313 = from_html(`<h2 class="slex-section-title"><!><!></h2>`);
31971
31891
  var root_65 = from_html(`<p class="slex-section-subtitle"> </p>`);
31972
31892
  var root_73 = from_html(`<a class="slex-section-action"> </a>`);
@@ -32017,7 +31937,7 @@ l0,-` + (midHeight + 144) + `c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949
32017
31937
  var node_4 = sibling(node_3);
32018
31938
  {
32019
31939
  var consequent_2 = ($$anchor4) => {
32020
- var span = root_57();
31940
+ var span = root_56();
32021
31941
  var text_2 = child(span, true);
32022
31942
  reset(span);
32023
31943
  template_effect(($0) => set_text(text_2, $0), [() => text2(get2(p).title)]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slexkit",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Zero-build, Markdown-friendly reactive UI runtime for AI output.",
5
5
  "author": "SlexKit contributors",
6
6
  "type": "module",
@@ -81,7 +81,7 @@
81
81
  ],
82
82
  "scripts": {
83
83
  "dev": "bun run site/server.ts",
84
- "build": "bun run build:core && bun run --filter @slexkit/streamdown build && bun run --filter @slexkit/obsidian build && bun run --filter @slexkit/mcp build",
84
+ "build": "bun run build:core && bun run --filter @slexkit/streamdown build && bun run --filter @slexkit/mcp build",
85
85
  "build:core": "bun run scripts/build-core.ts",
86
86
  "ai:docs": "bun run scripts/generate-ai-docs.ts",
87
87
  "version:sync": "bun run scripts/sync-version.ts",
@@ -120,6 +120,7 @@
120
120
  "flowbite": "^4.0.2",
121
121
  "flowbite-svelte": "^1.33.1",
122
122
  "katex": "^0.17.0",
123
+ "marked": "^18.0.5",
123
124
  "svelte": "^5.55.9",
124
125
  "svelte-highlight": "^7.9.0"
125
126
  },
@@ -21,7 +21,7 @@ Use this skill as `/host` when adding SlexKit to a host application or documenta
21
21
 
22
22
  - Vanilla host: `createSlexKitMarkdownRuntimeHost`.
23
23
  - React/Streamdown: `@slexkit/streamdown`.
24
- - Obsidian: `@slexkit/obsidian`, readonly fenced block rendering.
24
+ - Obsidian: install the official SlexKit plugin from Obsidian Community Plugins; release repo `slexkit/obsidian-slexkit`.
25
25
  - Custom host: detect the `slex` code fence, pass source plus artifact id to the runtime host, dispose when the block is removed.
26
26
 
27
27
  ## Rules
@@ -6,6 +6,19 @@
6
6
  let { props }: SvelteComponentProps = $props();
7
7
  let p = $state<PropValues>({});
8
8
  $effect(() => bindPropStore(props, (next) => (p = next)));
9
+
10
+ const color = $derived(p.color == null || p.color === "" ? undefined : text(p.color));
11
+ const size = $derived(cssLength(p.size));
12
+
13
+ function cssLength(value: unknown): string | undefined {
14
+ if (value == null || value === "") return undefined;
15
+ const rendered = text(value);
16
+ return /^-?\d+(\.\d+)?$/.test(rendered) ? `${rendered}px` : rendered;
17
+ }
9
18
  </script>
10
19
 
11
- <div class={`slex-text${p.variant ? ` slex-text--${text(p.variant)}` : ""}${p.class ? ` ${text(p.class)}` : ""}`}>{text(p.content ?? p.text ?? p.label)}</div>
20
+ <div
21
+ class={`slex-text${p.variant ? ` slex-text--${text(p.variant)}` : ""}${p.class ? ` ${text(p.class)}` : ""}`}
22
+ style:color={color}
23
+ style:font-size={size}
24
+ >{text(p.content ?? p.text ?? p.label)}</div>
@@ -34,7 +34,7 @@
34
34
  </script>
35
35
 
36
36
  <span class="slex-choice-event-layer" onpointerdown={() => haptic(8)} onclick={() => haptic(8)}>
37
- <label class="slex-checkbox-field">
37
+ <label class="slex-checkbox-field" data-disabled={p.disabled ? "true" : undefined}>
38
38
  <input
39
39
  type="checkbox"
40
40
  class="slex-checkbox"