@fewbox/den-web 0.2.0-preview.44 → 0.2.0-preview.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fewbox/den-web",
3
- "version": "0.2.0-preview.44",
3
+ "version": "0.2.0-preview.45",
4
4
  "main": "index.js",
5
5
  "types": "index-web.d.ts",
6
6
  "repository": "https://github.com/FewBox/fewbox-den.git",
@@ -2,7 +2,9 @@ import { fileURLToPath } from 'url';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
 
5
- const copyFolderAsync = (source, target) => {
5
+ const OVERWRITE_LIST = [path.join('.claude', 'skills') + path.sep];
6
+
7
+ const copyFolderAsync = (source, target, rootSource) => {
6
8
  fs.mkdirSync(target, { recursive: true });
7
9
  const entries = fs.readdirSync(source, { withFileTypes: true });
8
10
  for (let entry of entries) {
@@ -10,11 +12,17 @@ const copyFolderAsync = (source, target) => {
10
12
  const destPath = path.join(target, entry.name);
11
13
 
12
14
  if (entry.isDirectory()) {
13
- copyFolderAsync(srcPath, destPath);
15
+ copyFolderAsync(srcPath, destPath, rootSource);
14
16
  } else {
15
- if (fs.existsSync(destPath)) {
17
+ const rel = path.relative(rootSource, srcPath);
18
+ const forceOverwrite = OVERWRITE_LIST.some(prefix => rel.startsWith(prefix));
19
+ const exists = fs.existsSync(destPath);
20
+ if (exists && !forceOverwrite) {
16
21
  console.log(`You should merge '${destPath}' manually!`);
17
22
  } else {
23
+ if (exists) {
24
+ console.log(`Overwriting '${destPath}' with latest version.`);
25
+ }
18
26
  fs.copyFileSync(srcPath, destPath);
19
27
  }
20
28
  }
@@ -26,4 +34,4 @@ const rootdir = path.dirname(__filename);
26
34
  const projectRoot = process.env.INIT_CWD || process.cwd();
27
35
  const templateDir = path.join(rootdir, '../templates');
28
36
 
29
- copyFolderAsync(templateDir, projectRoot);
37
+ copyFolderAsync(templateDir, projectRoot, templateDir);
@@ -1,6 +1,10 @@
1
+ import { Property } from 'csstype';
1
2
  import { IBaseInputProps } from "..";
2
3
  export interface IVCheckBoxProps extends IBaseInputProps {
3
4
  isChecked?: boolean;
5
+ checkedSvg?: React.ReactNode;
6
+ uncheckedSvg?: React.ReactNode;
7
+ svgSize?: Property.Height;
4
8
  }
5
9
  declare const VCheckBox: (props: IVCheckBoxProps) => React.JSX.Element;
6
10
  export default VCheckBox;
@@ -1,6 +1,10 @@
1
+ import { Property } from 'csstype';
1
2
  import { IBaseInputProps } from "..";
2
3
  export interface IVRadioProps extends IBaseInputProps {
3
4
  isChecked?: boolean;
5
+ checkedSvg?: React.ReactNode;
6
+ uncheckedSvg?: React.ReactNode;
7
+ svgSize?: Property.Height;
4
8
  }
5
9
  declare const VRadio: (props: IVRadioProps) => React.JSX.Element;
6
10
  export default VRadio;
@@ -1,8 +1,15 @@
1
+ import { Property } from 'csstype';
2
+ import { FullGapType, FullPaddingType } from '../../Engine';
1
3
  import { IBaseProps, IBaseStates } from '../../Engine/Base';
2
4
  export interface IVSwitchProps extends IBaseProps {
3
5
  isOn: boolean;
4
6
  icon?: React.JSX.Element;
5
- gap?: string;
7
+ onIcon?: React.JSX.Element;
8
+ offIcon?: React.JSX.Element;
9
+ thumbSvg?: React.ReactNode;
10
+ thumbSize?: Property.Height;
11
+ trackPadding?: FullPaddingType;
12
+ gap?: FullGapType;
6
13
  isDisabled?: boolean;
7
14
  onSwitch?: (isOn: boolean) => void;
8
15
  }
@@ -64,7 +64,7 @@ All components extend `IBaseProps` (which extends `IViewProps`) providing these
64
64
  | `zIndex` | `Property.ZIndex` | CSS z-index |
65
65
  | `fontFamily` | `Property.FontFamily` | CSS font-family |
66
66
  | `letterSpacing` | `LetterSpacingType \| Property.LetterSpacing` | Letter spacing preset or custom CSS value |
67
- | `lineHeight` | `Property.LineHeight` | CSS line-height |
67
+ | `lineHeight` | `LineHeightType \| Property.LineHeight` | Line height preset or custom CSS value |
68
68
  | `selfShrink` | `number` | flex-shrink for the component itself |
69
69
  | `selfGrow` | `number` | flex-grow for the component itself |
70
70
  | `selfBasis` | `string` | flex-basis for the component itself |
@@ -165,6 +165,14 @@ GapType.Default | .Normal | .ExtraSmall | .Small | .Large | .ExtraLarge
165
165
  // Letter Spacing
166
166
  LetterSpacingType.Default | .Normal | .ExtraSmall | .Small | .Large | .ExtraLarge
167
167
 
168
+ // Line Height (Apple HIG-inspired scale)
169
+ LineHeightType.Default // inherits
170
+ LineHeightType.Normal // 1.0
171
+ LineHeightType.ExtraSmall // 1.15
172
+ LineHeightType.Small // 1.25
173
+ LineHeightType.Large // 1.35
174
+ LineHeightType.ExtraLarge // 1.45
175
+
168
176
  // Opacity
169
177
  OpacityType._0 | ._10 | ._20 | ._25 | ._30 | ._40 | ._50 | ._60 | ._70 | ._75 | ._80 | ._90 | ._100
170
178
 
@@ -495,6 +503,10 @@ Wrap a child in an S-component to override the parent's cross-axis alignment for
495
503
 
496
504
  // FlexItem also exports FlexItemAlignSelfType
497
505
  // Flex also exports FlexAlignContentType
506
+
507
+ // Note: Flex does NOT set overflow by default (as of 2026-03).
508
+ // Children can overflow the flex container unless you set overflow explicitly.
509
+ // Pass `overflow={OverflowType.Hidden}` if you want clipping.
498
510
  ```
499
511
 
500
512
  ---
@@ -698,6 +710,16 @@ const [value, setValue] = useState('');
698
710
  )}
699
711
  />
700
712
 
713
+ // Input-scoped color props (apply to the native <input> only, not the wrapper):
714
+ <VTextBox
715
+ name="form.email"
716
+ frontColor={ColorType.Dark} // wrapper text color; also applied to <input> if inputFrontColor is omitted
717
+ inputFrontColor={ColorType.Black} // <input> text color (overrides frontColor on input)
718
+ inputBackgroundColor={ColorType.White} // <input> background color
719
+ placeholderColor={ColorType.Placeholder} // placeholder text color
720
+ />
721
+ // Available on all VInput-based components (VTextBox, VEmail, VPassword, VNumber, VDate, VTextArea, VDropdown, etc.)
722
+
701
723
  // Other input types:
702
724
  <VEmail name="form.email" required placeholder="Email" />
703
725
  <VPassword name="form.password" placeholder="Password" />
@@ -725,10 +747,34 @@ const [value, setValue] = useState('');
725
747
  frontColor={ColorType.Primary}
726
748
  />
727
749
 
750
+ // Checkbox with custom SVG icons and size override.
751
+ // checkedSvg/uncheckedSvg replace the built-in checkbox icons.
752
+ // svgSize sets the inline height on VSvg, overriding --den-v-svg-size (default 2.2em).
753
+ <VCheckBox
754
+ name="form.liked"
755
+ label="Like"
756
+ isChecked={liked}
757
+ checkedSvg={<LikeFilledSvg />}
758
+ uncheckedSvg={<LikeOutlineSvg />}
759
+ svgSize="1.2em"
760
+ frontColor={ColorType.Error}
761
+ />
762
+
728
763
  // Radio
729
764
  <VRadio id="opt1" name="form.option" value="A" label="Option A" />
730
765
  <VRadio id="opt2" name="form.option" value="B" label="Option B" />
731
766
 
767
+ // Radio also accepts checkedSvg / uncheckedSvg / svgSize (same API as VCheckBox).
768
+ <VRadio
769
+ name="form.option"
770
+ value="A"
771
+ label="Option A"
772
+ isChecked={selected === 'A'}
773
+ checkedSvg={<StarFilledSvg />}
774
+ uncheckedSvg={<StarOutlineSvg />}
775
+ svgSize="1.2em"
776
+ />
777
+
732
778
  // Radio Group (managed state)
733
779
  <VGroup
734
780
  selectedValue="A"
@@ -772,6 +818,7 @@ const [value, setValue] = useState('');
772
818
  menuGap="4px" // gap between dropdown menu and trigger
773
819
  menuBackgroundColor={ColorType.White}
774
820
  menuZIndex={9999}
821
+ menuMaxHeight="300px" // scrollable menu when items exceed height
775
822
  handleChange={(value) => console.log(value)}
776
823
  overWriteDropdownMenu={(items) => <CustomMenu items={items} />} // custom menu renderer
777
824
  overWriteDropdownItem={(item) => <CustomItem item={item} />} // custom item renderer
@@ -781,10 +828,28 @@ const [value, setValue] = useState('');
781
828
  // Switch
782
829
  <VSwitch
783
830
  isOn={true}
784
- icon={<SwitchIcon />}
831
+ icon={<SwitchIcon />} // shown on the empty side in BOTH states (legacy single-icon prop)
785
832
  onSwitch={(isOn) => console.log(isOn)}
786
833
  />
787
834
 
835
+ // Switch with state-specific icons, custom thumb svg, custom thumb size, and track padding.
836
+ // onIcon shows on the right when isOn=true, offIcon on the left when isOn=false.
837
+ // onIcon/offIcon override `icon` when provided.
838
+ // thumbSvg replaces the built-in switch knob graphic.
839
+ // thumbSize sets the inline height on the thumb VSvg, overriding --den-v-svg-size.
840
+ // trackPadding controls inner spacing between SVGs and the colored track edge
841
+ // (default '0.2em'). Applied symmetrically — set to '0' for flush, larger values for roomier look.
842
+ <VSwitch
843
+ isOn={isOn}
844
+ onSwitch={setIsOn}
845
+ onIcon={<SunSvg />}
846
+ offIcon={<MoonSvg />}
847
+ thumbSvg={<StarSvg />}
848
+ thumbSize="1.5em"
849
+ trackPadding="0.4em"
850
+ frontColor={ColorType.Success}
851
+ />
852
+
788
853
  // File upload
789
854
  <VFile
790
855
  name="form.avatar"
@@ -792,6 +857,23 @@ const [value, setValue] = useState('');
792
857
  accept=".jpg,.png"
793
858
  appearance={<UploadIcon />} // Custom trigger element
794
859
  />
860
+
861
+ // Custom preview (sync or async) — e.g., render a cached image gallery.
862
+ // `reload` re-triggers renderPreview (e.g., after cache refresh).
863
+ <VFile
864
+ name="form.photos"
865
+ multiple
866
+ renderPreview={(inputFiles, isLoading, reload) => (
867
+ <XWrapEvenly gap="0.5em">
868
+ {inputFiles.map((f, i) => (
869
+ <VImage key={i} src={f.objectUrl} category={ImageCategory.Squared} width="80px" />
870
+ ))}
871
+ </XWrapEvenly>
872
+ )}
873
+ />
874
+ // renderPreview signature: (inputFiles: InputFile[], isLoading: boolean, reload: () => void) => JSX.Element | Promise<JSX.Element>
875
+ // InputFile: { file: File; objectUrl?: string; ... }
876
+ // Async renderPreview shows `appearance` as fallback until the promise resolves.
795
877
  // FileCategory enum available for file categories
796
878
 
797
879
  // File with base64 output