@jsenv/navi 0.5.3 → 0.6.0

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.
@@ -18506,6 +18506,162 @@ const useConstraints = (elementRef, constraints, targetSelector) => {
18506
18506
  }, constraints);
18507
18507
  };
18508
18508
 
18509
+ /**
18510
+ * Merges a component's base style with style received from props.
18511
+ *
18512
+ * ```jsx
18513
+ * const MyButton = ({ style, children }) => (
18514
+ * <button style={withPropsStyle({ padding: '10px' }, style)}>
18515
+ * {children}
18516
+ * </button>
18517
+ * );
18518
+ *
18519
+ * // Usage:
18520
+ * <MyButton style={{ color: 'red', fontSize: '14px' }} />
18521
+ * <MyButton style="color: blue; margin: 5px;" />
18522
+ * <MyButton /> // Just base styles
18523
+ * ```
18524
+ *
18525
+ * @param {string|object} baseStyle - The component's base style (string or object)
18526
+ * @param {string|object} [styleFromProps] - Additional style from props (optional)
18527
+ * @returns {object} The merged style object
18528
+ */
18529
+ const withPropsStyle = (baseStyle, styleFromProps) => {
18530
+ if (!styleFromProps) {
18531
+ return baseStyle;
18532
+ }
18533
+ if (!baseStyle) {
18534
+ return styleFromProps;
18535
+ }
18536
+
18537
+ // Parse base style to object if it's a string
18538
+ const parsedBaseStyle =
18539
+ typeof baseStyle === "string"
18540
+ ? parseStyleString(baseStyle)
18541
+ : baseStyle || {};
18542
+ // Parse props style to object if it's a string
18543
+ const parsedPropsStyle =
18544
+ typeof styleFromProps === "string"
18545
+ ? parseStyleString(styleFromProps)
18546
+ : styleFromProps;
18547
+ // Merge styles with props taking priority
18548
+ return { ...parsedBaseStyle, ...parsedPropsStyle };
18549
+ };
18550
+
18551
+ /**
18552
+ * Parses a CSS style string into a style object.
18553
+ * Handles CSS properties with proper camelCase conversion.
18554
+ *
18555
+ * @param {string} styleString - CSS style string like "color: red; font-size: 14px;"
18556
+ * @returns {object} Style object with camelCase properties
18557
+ */
18558
+ const parseStyleString = (styleString) => {
18559
+ const style = {};
18560
+
18561
+ if (!styleString || typeof styleString !== "string") {
18562
+ return style;
18563
+ }
18564
+
18565
+ // Split by semicolon and process each declaration
18566
+ const declarations = styleString.split(";");
18567
+
18568
+ for (let declaration of declarations) {
18569
+ declaration = declaration.trim();
18570
+ if (!declaration) continue;
18571
+
18572
+ const colonIndex = declaration.indexOf(":");
18573
+ if (colonIndex === -1) continue;
18574
+
18575
+ const property = declaration.slice(0, colonIndex).trim();
18576
+ const value = declaration.slice(colonIndex + 1).trim();
18577
+
18578
+ if (property && value) {
18579
+ // CSS custom properties (starting with --) should NOT be converted to camelCase
18580
+ if (property.startsWith("--")) {
18581
+ style[property] = value;
18582
+ } else {
18583
+ // Convert kebab-case to camelCase (e.g., "font-size" -> "fontSize")
18584
+ const camelCaseProperty = property.replace(
18585
+ /-([a-z])/g,
18586
+ (match, letter) => letter.toUpperCase(),
18587
+ );
18588
+ style[camelCaseProperty] = value;
18589
+ }
18590
+ }
18591
+ }
18592
+
18593
+ return style;
18594
+ };
18595
+
18596
+ const getStyleForSpacingProps = ({
18597
+ margin,
18598
+ marginX,
18599
+ marginY,
18600
+ marginLeft,
18601
+ marginTop,
18602
+ marginBottom,
18603
+ marginRight,
18604
+ padding,
18605
+ paddingX,
18606
+ paddingY,
18607
+ paddingLeft,
18608
+ paddingTop,
18609
+ paddingBottom,
18610
+ paddingRight
18611
+ }) => {
18612
+ const style = {};
18613
+ if (margin !== undefined) {
18614
+ style.margin = margin;
18615
+ }
18616
+ const effectiveMarginLeft = marginLeft ?? marginX;
18617
+ const effectiveMarginRight = marginRight ?? marginX;
18618
+ const effectiveMarginTop = marginTop ?? marginY;
18619
+ const effectiveMarginBottom = marginBottom ?? marginY;
18620
+ if (effectiveMarginLeft !== undefined) {
18621
+ style.marginLeft = effectiveMarginLeft;
18622
+ }
18623
+ if (effectiveMarginRight !== undefined) {
18624
+ style.marginRight = effectiveMarginRight;
18625
+ }
18626
+ if (effectiveMarginTop !== undefined) {
18627
+ style.marginTop = effectiveMarginTop;
18628
+ }
18629
+ if (effectiveMarginBottom !== undefined) {
18630
+ style.marginBottom = effectiveMarginBottom;
18631
+ }
18632
+ if (padding !== undefined) {
18633
+ style.padding = padding;
18634
+ }
18635
+ const effectivePaddingLeft = paddingLeft ?? paddingX;
18636
+ const effectivePaddingRight = paddingRight ?? paddingX;
18637
+ const effectivePaddingTop = paddingTop ?? paddingY;
18638
+ const effectivePaddingBottom = paddingBottom ?? paddingY;
18639
+ if (effectivePaddingLeft !== undefined) {
18640
+ style.paddingLeft = effectivePaddingLeft;
18641
+ }
18642
+ if (effectivePaddingRight !== undefined) {
18643
+ style.paddingRight = effectivePaddingRight;
18644
+ }
18645
+ if (effectivePaddingTop !== undefined) {
18646
+ style.paddingTop = effectivePaddingTop;
18647
+ }
18648
+ if (effectivePaddingBottom !== undefined) {
18649
+ style.paddingBottom = effectivePaddingBottom;
18650
+ }
18651
+ return style;
18652
+ };
18653
+ const Spacing = ({
18654
+ style,
18655
+ children,
18656
+ ...rest
18657
+ }) => {
18658
+ const styleForSpacing = getStyleForSpacingProps(rest);
18659
+ return jsx("div", {
18660
+ style: withPropsStyle(styleForSpacing, style),
18661
+ children: children
18662
+ });
18663
+ };
18664
+
18509
18665
  const useNetworkSpeed = () => {
18510
18666
  return networkSpeedSignal.value;
18511
18667
  };
@@ -20057,16 +20213,17 @@ const NaviCheckbox = ({
20057
20213
  useLayoutEffect(() => {
20058
20214
  return initCustomField(ref.current, inputRef.current);
20059
20215
  }, []);
20216
+ const innerStyle = withPropsStyle({
20217
+ ...(accentColor ? {
20218
+ "--accent-color": accentColor
20219
+ } : {}),
20220
+ ...getStyleForSpacingProps(rest)
20221
+ }, style);
20060
20222
  return jsxs("div", {
20061
20223
  ...rest,
20062
20224
  ref: ref,
20063
20225
  className: "navi_checkbox",
20064
- style: {
20065
- ...(accentColor ? {
20066
- "--accent-color": accentColor
20067
- } : {}),
20068
- ...style
20069
- },
20226
+ style: innerStyle,
20070
20227
  "data-readonly": readOnly ? "" : undefined,
20071
20228
  "data-disabled": disabled ? "" : undefined,
20072
20229
  children: [children, jsx("div", {
@@ -20481,16 +20638,17 @@ const NaviRadio = ({
20481
20638
  useLayoutEffect(() => {
20482
20639
  return initCustomField(ref.current, inputRef.current);
20483
20640
  }, []);
20641
+ const innerStyle = withPropsStyle({
20642
+ ...(accentColor ? {
20643
+ "--accent-color": accentColor
20644
+ } : {}),
20645
+ ...getStyleForSpacingProps(rest)
20646
+ }, style);
20484
20647
  return jsxs("span", {
20485
20648
  ...rest,
20486
20649
  ref: ref,
20487
20650
  className: "navi_radio",
20488
- style: {
20489
- ...(accentColor ? {
20490
- "--accent-color": accentColor
20491
- } : {}),
20492
- ...style
20493
- },
20651
+ style: innerStyle,
20494
20652
  "data-readonly": readOnly ? "" : undefined,
20495
20653
  "data-disabled": disabled ? "" : undefined,
20496
20654
  children: [children, jsx("span", {
@@ -20566,93 +20724,6 @@ const withPropsClassName = (baseClassName, classNameFromProps) => {
20566
20724
  return `${baseClassName} ${normalizedPropsClassName}`;
20567
20725
  };
20568
20726
 
20569
- /**
20570
- * Merges a component's base style with style received from props.
20571
- *
20572
- * ```jsx
20573
- * const MyButton = ({ style, children }) => (
20574
- * <button style={withPropsStyle({ padding: '10px' }, style)}>
20575
- * {children}
20576
- * </button>
20577
- * );
20578
- *
20579
- * // Usage:
20580
- * <MyButton style={{ color: 'red', fontSize: '14px' }} />
20581
- * <MyButton style="color: blue; margin: 5px;" />
20582
- * <MyButton /> // Just base styles
20583
- * ```
20584
- *
20585
- * @param {string|object} baseStyle - The component's base style (string or object)
20586
- * @param {string|object} [styleFromProps] - Additional style from props (optional)
20587
- * @returns {object} The merged style object
20588
- */
20589
- const withPropsStyle = (baseStyle, styleFromProps) => {
20590
- if (!styleFromProps) {
20591
- return baseStyle;
20592
- }
20593
- if (!baseStyle) {
20594
- return styleFromProps;
20595
- }
20596
-
20597
- // Parse base style to object if it's a string
20598
- const parsedBaseStyle =
20599
- typeof baseStyle === "string"
20600
- ? parseStyleString(baseStyle)
20601
- : baseStyle || {};
20602
- // Parse props style to object if it's a string
20603
- const parsedPropsStyle =
20604
- typeof styleFromProps === "string"
20605
- ? parseStyleString(styleFromProps)
20606
- : styleFromProps;
20607
- // Merge styles with props taking priority
20608
- return { ...parsedBaseStyle, ...parsedPropsStyle };
20609
- };
20610
-
20611
- /**
20612
- * Parses a CSS style string into a style object.
20613
- * Handles CSS properties with proper camelCase conversion.
20614
- *
20615
- * @param {string} styleString - CSS style string like "color: red; font-size: 14px;"
20616
- * @returns {object} Style object with camelCase properties
20617
- */
20618
- const parseStyleString = (styleString) => {
20619
- const style = {};
20620
-
20621
- if (!styleString || typeof styleString !== "string") {
20622
- return style;
20623
- }
20624
-
20625
- // Split by semicolon and process each declaration
20626
- const declarations = styleString.split(";");
20627
-
20628
- for (let declaration of declarations) {
20629
- declaration = declaration.trim();
20630
- if (!declaration) continue;
20631
-
20632
- const colonIndex = declaration.indexOf(":");
20633
- if (colonIndex === -1) continue;
20634
-
20635
- const property = declaration.slice(0, colonIndex).trim();
20636
- const value = declaration.slice(colonIndex + 1).trim();
20637
-
20638
- if (property && value) {
20639
- // CSS custom properties (starting with --) should NOT be converted to camelCase
20640
- if (property.startsWith("--")) {
20641
- style[property] = value;
20642
- } else {
20643
- // Convert kebab-case to camelCase (e.g., "font-size" -> "fontSize")
20644
- const camelCaseProperty = property.replace(
20645
- /-([a-z])/g,
20646
- (match, letter) => letter.toUpperCase(),
20647
- );
20648
- style[camelCaseProperty] = value;
20649
- }
20650
- }
20651
- }
20652
-
20653
- return style;
20654
- };
20655
-
20656
20727
  installImportMetaCss(import.meta);import.meta.css = /* css */`
20657
20728
  @layer navi {
20658
20729
  .navi_input {
@@ -20788,15 +20859,17 @@ const InputTextualBasic = forwardRef((props, ref) => {
20788
20859
  autoSelect
20789
20860
  });
20790
20861
  useConstraints(innerRef, constraints);
20791
- const innerStyle = {
20862
+ const innerClassName = withPropsClassName(appearance === "navi" ? "navi_input" : undefined, className);
20863
+ const innerStyle = withPropsStyle({
20792
20864
  width,
20793
- height
20794
- };
20865
+ height,
20866
+ ...getStyleForSpacingProps(rest)
20867
+ }, style);
20795
20868
  const inputTextual = jsx("input", {
20796
20869
  ...rest,
20797
20870
  ref: innerRef,
20798
- className: withPropsClassName(appearance === "navi" ? "navi_input" : undefined, className),
20799
- style: withPropsStyle(innerStyle, style),
20871
+ className: innerClassName,
20872
+ style: innerStyle,
20800
20873
  type: type,
20801
20874
  "data-value": uiState,
20802
20875
  value: innerValue,
@@ -21401,7 +21474,6 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
21401
21474
  /* Active */
21402
21475
  .navi_button[data-active] .navi_button_content {
21403
21476
  --outline-color: var(--border-color-active);
21404
- --background-color: none;
21405
21477
  transform: scale(0.9);
21406
21478
  }
21407
21479
  .navi_button[data-active] .navi_button_shadow {
@@ -21514,6 +21586,7 @@ const ButtonBasic = forwardRef((props, ref) => {
21514
21586
  buttonChildren = children;
21515
21587
  }
21516
21588
  const innerStyle = {
21589
+ ...getStyleForSpacingProps(rest),
21517
21590
  "align-self": alignXMapping[alignX]
21518
21591
  };
21519
21592
  return jsx("button", {
@@ -27956,11 +28029,24 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
27956
28029
  `;
27957
28030
  const Text = ({
27958
28031
  children,
28032
+ color,
28033
+ bold,
28034
+ italic,
28035
+ underline,
28036
+ style,
27959
28037
  ...rest
27960
28038
  }) => {
28039
+ const innerStyle = withPropsStyle({
28040
+ color,
28041
+ fontWeight: bold ? "bold" : undefined,
28042
+ fontStyle: italic ? "italic" : undefined,
28043
+ textDecoration: underline ? "underline" : undefined,
28044
+ ...getStyleForSpacingProps(rest)
28045
+ }, style);
27961
28046
  return jsx("span", {
27962
28047
  ...rest,
27963
28048
  className: "navi_text",
28049
+ style: innerStyle,
27964
28050
  children: children
27965
28051
  });
27966
28052
  };
@@ -28098,4 +28184,4 @@ const useDependenciesDiff = (inputs) => {
28098
28184
  return diffRef.current;
28099
28185
  };
28100
28186
 
28101
- export { ActionRenderer, ActiveKeyboardShortcuts, Button, Checkbox, CheckboxList, Col, Colgroup, Details, Editable, ErrorBoundaryContext, FontSizedSvg, Form, Icon, IconAndText, Input, Label, Link, LinkWithIcon, Overflow, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, Select, SelectionContext, SummaryMarker, Tab, TabList, Table, TableCell, Tbody, Text, TextAndCount, Thead, Tr, UITransition, actionIntegratedVia, addCustomMessage, createAction, createSelectionKeyboardShortcuts, createUniqueValueConstraint, defineRoutes, enableDebugActions, enableDebugOnDocumentLoading, goBack, goForward, goTo, isCellSelected, isColumnSelected, isRowSelected, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useCellsAndColumns, useDependenciesDiff, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, valueInLocalStorage };
28187
+ export { ActionRenderer, ActiveKeyboardShortcuts, Button, Checkbox, CheckboxList, Col, Colgroup, Details, Editable, ErrorBoundaryContext, FontSizedSvg, Form, Icon, IconAndText, Input, Label, Link, LinkWithIcon, Overflow, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, Select, SelectionContext, Spacing, SummaryMarker, Tab, TabList, Table, TableCell, Tbody, Text, TextAndCount, Thead, Tr, UITransition, actionIntegratedVia, addCustomMessage, createAction, createSelectionKeyboardShortcuts, createUniqueValueConstraint, defineRoutes, enableDebugActions, enableDebugOnDocumentLoading, goBack, goForward, goTo, isCellSelected, isColumnSelected, isRowSelected, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useCellsAndColumns, useDependenciesDiff, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, valueInLocalStorage };
package/index.js CHANGED
@@ -92,6 +92,8 @@ export { Icon, Text } from "./src/components/text/text.jsx";
92
92
  export { TextAndCount } from "./src/components/text/text_and_count.jsx";
93
93
  // Callout, dialogs, ...
94
94
  export { openCallout } from "./src/components/callout/callout.js";
95
+ // Layout
96
+ export { Spacing } from "./src/components/layout/spacing.jsx";
95
97
 
96
98
  // Validation
97
99
  export { createUniqueValueConstraint } from "./src/validation/constraints/create_unique_value_constraint.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.5.3",
3
+ "version": "0.6.0",
4
4
  "description": "Library of components including navigation to create frontend applications",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,6 +14,7 @@ import { FormActionContext } from "../action_execution/form_context.js";
14
14
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
15
15
  import { useAction } from "../action_execution/use_action.js";
16
16
  import { useExecuteAction } from "../action_execution/use_execute_action.js";
17
+ import { getStyleForSpacingProps } from "../layout/spacing.jsx";
17
18
  import { LoaderBackground } from "../loader/loader_background.jsx";
18
19
  import { withPropsClassName } from "../props_composition/with_props_class_name.js";
19
20
  import { withPropsStyle } from "../props_composition/with_props_style.js";
@@ -125,7 +126,6 @@ import.meta.css = /* css */ `
125
126
  /* Active */
126
127
  .navi_button[data-active] .navi_button_content {
127
128
  --outline-color: var(--border-color-active);
128
- --background-color: none;
129
129
  transform: scale(0.9);
130
130
  }
131
131
  .navi_button[data-active] .navi_button_shadow {
@@ -242,6 +242,7 @@ const ButtonBasic = forwardRef((props, ref) => {
242
242
  }
243
243
 
244
244
  const innerStyle = {
245
+ ...getStyleForSpacingProps(rest),
245
246
  "align-self": alignXMapping[alignX],
246
247
  };
247
248
 
@@ -13,10 +13,12 @@ import { useConstraints } from "../../validation/hooks/use_constraints.js";
13
13
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
14
14
  import { useActionBoundToOneParam } from "../action_execution/use_action.js";
15
15
  import { useExecuteAction } from "../action_execution/use_execute_action.js";
16
+ import { getStyleForSpacingProps } from "../layout/spacing.jsx";
16
17
  import {
17
18
  LoadableInlineElement,
18
19
  LoaderBackground,
19
20
  } from "../loader/loader_background.jsx";
21
+ import { withPropsStyle } from "../props_composition/with_props_style.js";
20
22
  import { useAutoFocus } from "../use_auto_focus.js";
21
23
  import { initCustomField } from "./custom_field.js";
22
24
  import {
@@ -331,15 +333,20 @@ const NaviCheckbox = ({
331
333
  return initCustomField(ref.current, inputRef.current);
332
334
  }, []);
333
335
 
336
+ const innerStyle = withPropsStyle(
337
+ {
338
+ ...(accentColor ? { "--accent-color": accentColor } : {}),
339
+ ...getStyleForSpacingProps(rest),
340
+ },
341
+ style,
342
+ );
343
+
334
344
  return (
335
345
  <div
336
346
  {...rest}
337
347
  ref={ref}
338
348
  className="navi_checkbox"
339
- style={{
340
- ...(accentColor ? { "--accent-color": accentColor } : {}),
341
- ...style,
342
- }}
349
+ style={innerStyle}
343
350
  data-readonly={readOnly ? "" : undefined}
344
351
  data-disabled={disabled ? "" : undefined}
345
352
  >
@@ -8,10 +8,12 @@ import {
8
8
 
9
9
  import { useConstraints } from "../../validation/hooks/use_constraints.js";
10
10
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
11
+ import { getStyleForSpacingProps } from "../layout/spacing.jsx";
11
12
  import {
12
13
  LoadableInlineElement,
13
14
  LoaderBackground,
14
15
  } from "../loader/loader_background.jsx";
16
+ import { withPropsStyle } from "../props_composition/with_props_style.js";
15
17
  import { useAutoFocus } from "../use_auto_focus.js";
16
18
  import { initCustomField } from "./custom_field.js";
17
19
  import {
@@ -370,15 +372,20 @@ const NaviRadio = ({
370
372
  return initCustomField(ref.current, inputRef.current);
371
373
  }, []);
372
374
 
375
+ const innerStyle = withPropsStyle(
376
+ {
377
+ ...(accentColor ? { "--accent-color": accentColor } : {}),
378
+ ...getStyleForSpacingProps(rest),
379
+ },
380
+ style,
381
+ );
382
+
373
383
  return (
374
384
  <span
375
385
  {...rest}
376
386
  ref={ref}
377
387
  className="navi_radio"
378
- style={{
379
- ...(accentColor ? { "--accent-color": accentColor } : {}),
380
- ...style,
381
- }}
388
+ style={innerStyle}
382
389
  data-readonly={readOnly ? "" : undefined}
383
390
  data-disabled={disabled ? "" : undefined}
384
391
  >
@@ -31,6 +31,7 @@ import { useConstraints } from "../../validation/hooks/use_constraints.js";
31
31
  import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
32
32
  import { useActionBoundToOneParam } from "../action_execution/use_action.js";
33
33
  import { useExecuteAction } from "../action_execution/use_execute_action.js";
34
+ import { getStyleForSpacingProps } from "../layout/spacing.jsx";
34
35
  import { LoadableInlineElement } from "../loader/loader_background.jsx";
35
36
  import { withPropsClassName } from "../props_composition/with_props_class_name.js";
36
37
  import { withPropsStyle } from "../props_composition/with_props_style.js";
@@ -194,19 +195,24 @@ const InputTextualBasic = forwardRef((props, ref) => {
194
195
  });
195
196
  useConstraints(innerRef, constraints);
196
197
 
197
- const innerStyle = {
198
- width,
199
- height,
200
- };
198
+ const innerClassName = withPropsClassName(
199
+ appearance === "navi" ? "navi_input" : undefined,
200
+ className,
201
+ );
202
+ const innerStyle = withPropsStyle(
203
+ {
204
+ width,
205
+ height,
206
+ ...getStyleForSpacingProps(rest),
207
+ },
208
+ style,
209
+ );
201
210
  const inputTextual = (
202
211
  <input
203
212
  {...rest}
204
213
  ref={innerRef}
205
- className={withPropsClassName(
206
- appearance === "navi" ? "navi_input" : undefined,
207
- className,
208
- )}
209
- style={withPropsStyle(innerStyle, style)}
214
+ className={innerClassName}
215
+ style={innerStyle}
210
216
  type={type}
211
217
  data-value={uiState}
212
218
  value={innerValue}
@@ -0,0 +1,68 @@
1
+ import { withPropsStyle } from "../props_composition/with_props_style.js";
2
+
3
+ export const getStyleForSpacingProps = ({
4
+ margin,
5
+ marginX,
6
+ marginY,
7
+ marginLeft,
8
+ marginTop,
9
+ marginBottom,
10
+ marginRight,
11
+ padding,
12
+ paddingX,
13
+ paddingY,
14
+ paddingLeft,
15
+ paddingTop,
16
+ paddingBottom,
17
+ paddingRight,
18
+ }) => {
19
+ const style = {};
20
+
21
+ if (margin !== undefined) {
22
+ style.margin = margin;
23
+ }
24
+ const effectiveMarginLeft = marginLeft ?? marginX;
25
+ const effectiveMarginRight = marginRight ?? marginX;
26
+ const effectiveMarginTop = marginTop ?? marginY;
27
+ const effectiveMarginBottom = marginBottom ?? marginY;
28
+
29
+ if (effectiveMarginLeft !== undefined) {
30
+ style.marginLeft = effectiveMarginLeft;
31
+ }
32
+ if (effectiveMarginRight !== undefined) {
33
+ style.marginRight = effectiveMarginRight;
34
+ }
35
+ if (effectiveMarginTop !== undefined) {
36
+ style.marginTop = effectiveMarginTop;
37
+ }
38
+ if (effectiveMarginBottom !== undefined) {
39
+ style.marginBottom = effectiveMarginBottom;
40
+ }
41
+
42
+ if (padding !== undefined) {
43
+ style.padding = padding;
44
+ }
45
+ const effectivePaddingLeft = paddingLeft ?? paddingX;
46
+ const effectivePaddingRight = paddingRight ?? paddingX;
47
+ const effectivePaddingTop = paddingTop ?? paddingY;
48
+ const effectivePaddingBottom = paddingBottom ?? paddingY;
49
+ if (effectivePaddingLeft !== undefined) {
50
+ style.paddingLeft = effectivePaddingLeft;
51
+ }
52
+ if (effectivePaddingRight !== undefined) {
53
+ style.paddingRight = effectivePaddingRight;
54
+ }
55
+ if (effectivePaddingTop !== undefined) {
56
+ style.paddingTop = effectivePaddingTop;
57
+ }
58
+ if (effectivePaddingBottom !== undefined) {
59
+ style.paddingBottom = effectivePaddingBottom;
60
+ }
61
+
62
+ return style;
63
+ };
64
+
65
+ export const Spacing = ({ style, children, ...rest }) => {
66
+ const styleForSpacing = getStyleForSpacingProps(rest);
67
+ return <div style={withPropsStyle(styleForSpacing, style)}>{children}</div>;
68
+ };
@@ -160,20 +160,6 @@
160
160
  <SearchIcon />
161
161
  </Icon>
162
162
  </Text>
163
-
164
- <Text>
165
- Favorites
166
- <Icon>
167
- <StarIcon />
168
- </Icon>
169
- </Text>
170
-
171
- <Text>
172
- Liked
173
- <Icon>
174
- <HeartIcon />
175
- </Icon>
176
- </Text>
177
163
  </div>
178
164
  </section>
179
165
 
@@ -205,6 +191,32 @@
205
191
  </Icon>
206
192
  Two on the left
207
193
  </Text>
194
+
195
+ <Text>
196
+ Two on the right
197
+ <Icon>
198
+ <StarIcon />
199
+ </Icon>
200
+ <Icon>
201
+ <HeartIcon />
202
+ </Icon>
203
+ </Text>
204
+
205
+ <Text>
206
+ <Icon>
207
+ <HomeIcon />
208
+ </Icon>
209
+ <Icon>
210
+ <UserIcon />
211
+ </Icon>
212
+ Two on the left and right
213
+ <Icon>
214
+ <StarIcon />
215
+ </Icon>
216
+ <Icon>
217
+ <HeartIcon />
218
+ </Icon>
219
+ </Text>
208
220
  </div>
209
221
  </section>
210
222
 
@@ -312,44 +324,6 @@
312
324
  Search Files
313
325
  </Text>
314
326
  </button>
315
-
316
- <button
317
- style={{
318
- padding: "10px 15px",
319
- border: "none",
320
- borderRadius: "4px",
321
- background: "#007bff",
322
- color: "white",
323
- cursor: "pointer",
324
- fontSize: "14px",
325
- }}
326
- >
327
- <Text>
328
- <Icon>
329
- <UserIcon />
330
- </Icon>
331
- Create Account
332
- </Text>
333
- </button>
334
-
335
- <button
336
- style={{
337
- padding: "10px 15px",
338
- border: "1px solid #dc3545",
339
- borderRadius: "4px",
340
- background: "transparent",
341
- color: "#dc3545",
342
- cursor: "pointer",
343
- fontSize: "14px",
344
- }}
345
- >
346
- <Text>
347
- <Icon>
348
- <HeartIcon />
349
- </Icon>
350
- Add to Favorites
351
- </Text>
352
- </button>
353
327
  </div>
354
328
  </section>
355
329
 
@@ -369,20 +343,6 @@
369
343
  gap: "15px",
370
344
  }}
371
345
  >
372
- <Text
373
- style={{
374
- cursor: "pointer",
375
- padding: "8px 12px",
376
- borderRadius: "4px",
377
- transition: "background-color 0.2s",
378
- }}
379
- >
380
- <Icon>
381
- <HomeIcon />
382
- </Icon>
383
- Dashboard
384
- </Text>
385
-
386
346
  <Text
387
347
  style={{
388
348
  cursor: "pointer",
@@ -397,19 +357,6 @@
397
357
  </Icon>
398
358
  Users
399
359
  </Text>
400
-
401
- <Text
402
- style={{
403
- cursor: "pointer",
404
- padding: "8px 12px",
405
- borderRadius: "4px",
406
- }}
407
- >
408
- <Icon>
409
- <SettingsIcon />
410
- </Icon>
411
- Settings
412
- </Text>
413
360
  </div>
414
361
  </nav>
415
362
  </section>
@@ -418,41 +365,50 @@
418
365
  <h2>Inline Text with Icons</h2>
419
366
  <p style={{ fontSize: "16px", lineHeight: "1.6" }}>
420
367
  Welcome to our platform! Click on the{" "}
421
- <Text>
368
+ <Text bold>
422
369
  <Icon>
423
370
  <HomeIcon />
424
371
  </Icon>
425
372
  home
426
373
  </Text>{" "}
427
374
  button to return to the dashboard, or visit your{" "}
428
- <Text>
375
+ <Text italic>
429
376
  <Icon>
430
377
  <UserIcon />
431
378
  </Icon>
432
379
  profile
433
380
  </Text>{" "}
434
381
  to update your settings. Don't forget to{" "}
435
- <Text>
382
+ <Text underline>
436
383
  <Icon>
437
384
  <StarIcon />
438
385
  </Icon>
439
386
  star
440
387
  </Text>{" "}
441
388
  your favorite items and{" "}
442
- <Text>
389
+ <Text bold italic>
443
390
  <Icon>
444
391
  <HeartIcon />
445
392
  </Icon>
446
393
  like
447
394
  </Text>{" "}
448
395
  the content you enjoy. Use the{" "}
449
- <Text>
396
+ <Text bold underline>
450
397
  <Icon>
451
398
  <SearchIcon />
452
399
  </Icon>
453
400
  search
454
401
  </Text>{" "}
455
- feature to find what you're looking for quickly.
402
+ feature to find what you're looking for quickly. You can also
403
+ combine{" "}
404
+ <Text italic underline>
405
+ multiple styles
406
+ </Text>{" "}
407
+ together for{" "}
408
+ <Text bold italic underline>
409
+ maximum emphasis
410
+ </Text>
411
+ !
456
412
  </p>
457
413
  </section>
458
414
  </div>
@@ -1,3 +1,6 @@
1
+ import { getStyleForSpacingProps } from "../layout/spacing.jsx";
2
+ import { withPropsStyle } from "../props_composition/with_props_style.js";
3
+
1
4
  import.meta.css = /* css */ `
2
5
  :root {
3
6
  --navi-icon-align-y: center;
@@ -21,9 +24,28 @@ import.meta.css = /* css */ `
21
24
  }
22
25
  `;
23
26
 
24
- export const Text = ({ children, ...rest }) => {
27
+ export const Text = ({
28
+ children,
29
+ color,
30
+ bold,
31
+ italic,
32
+ underline,
33
+ style,
34
+ ...rest
35
+ }) => {
36
+ const innerStyle = withPropsStyle(
37
+ {
38
+ color,
39
+ fontWeight: bold ? "bold" : undefined,
40
+ fontStyle: italic ? "italic" : undefined,
41
+ textDecoration: underline ? "underline" : undefined,
42
+ ...getStyleForSpacingProps(rest),
43
+ },
44
+ style,
45
+ );
46
+
25
47
  return (
26
- <span {...rest} className="navi_text">
48
+ <span {...rest} className="navi_text" style={innerStyle}>
27
49
  {children}
28
50
  </span>
29
51
  );