@jsenv/navi 0.6.2 → 0.7.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.
@@ -11735,7 +11735,7 @@ const openCallout = (
11735
11735
  level = "warning",
11736
11736
  onClose,
11737
11737
  closeOnClickOutside = level === "info",
11738
- hideErrorStack,
11738
+ showErrorStack,
11739
11739
  debug = false,
11740
11740
  } = {},
11741
11741
  ) => {
@@ -11803,7 +11803,7 @@ const openCallout = (
11803
11803
  if (Error.isError(newMessage)) {
11804
11804
  const error = newMessage;
11805
11805
  newMessage = error.message;
11806
- if (!hideErrorStack && error.stack) {
11806
+ if (showErrorStack && error.stack) {
11807
11807
  newMessage += `<pre class="navi_callout_error_stack">${escapeHtml(String(error.stack))}</pre>`;
11808
11808
  }
11809
11809
  }
@@ -13766,6 +13766,7 @@ const useExecuteAction = (
13766
13766
  elementRef,
13767
13767
  {
13768
13768
  errorEffect = "show_validation_message", // "show_validation_message" or "throw"
13769
+ errorMapping,
13769
13770
  } = {},
13770
13771
  ) => {
13771
13772
  // see https://medium.com/trabe/catching-asynchronous-errors-in-react-using-error-boundaries-5e8a5fd7b971
@@ -13783,7 +13784,8 @@ const useExecuteAction = (
13783
13784
  const validationMessageTargetRef = useRef(null);
13784
13785
  const addErrorMessage = (error) => {
13785
13786
  const validationMessageTarget = validationMessageTargetRef.current;
13786
- addCustomMessage(validationMessageTarget, "action_error", error, {
13787
+ const errorMapped = errorMapping ? errorMapping(error) : error;
13788
+ addCustomMessage(validationMessageTarget, "action_error", errorMapped, {
13787
13789
  // This error should not prevent <form> submission
13788
13790
  // so whenever user tries to submit the form the error is cleared
13789
13791
  // (Hitting enter key, clicking on submit button, etc. would allow to re-submit the form in error state)
@@ -18594,74 +18596,84 @@ const parseStyleString = (styleString) => {
18594
18596
  };
18595
18597
 
18596
18598
  const consumeSpacingProps = props => {
18597
- const consume = name => {
18598
- if (Object.hasOwn(props, name)) {
18599
- const value = props[name];
18600
- delete props[name];
18601
- return value;
18602
- }
18603
- return undefined;
18604
- };
18605
- const margin = consume("margin");
18606
- const marginX = consume("marginX");
18607
- const marginY = consume("marginY");
18608
- const marginLeft = consume("marginLeft");
18609
- const marginRight = consume("marginRight");
18610
- const marginTop = consume("marginTop");
18611
- const marginBottom = consume("marginBottom");
18612
18599
  const style = {};
18613
- if (margin !== undefined) {
18614
- style.margin = margin;
18615
- }
18616
- if (marginLeft !== undefined) {
18617
- style.marginLeft = marginLeft;
18618
- } else if (marginX !== undefined) {
18619
- style.marginLeft = marginX;
18620
- }
18621
- if (marginRight !== undefined) {
18622
- style.marginRight = marginRight;
18623
- } else if (marginX !== undefined) {
18624
- style.marginRight = marginX;
18625
- }
18626
- if (marginTop !== undefined) {
18627
- style.marginTop = marginTop;
18628
- } else if (marginY !== undefined) {
18629
- style.marginTop = marginY;
18630
- }
18631
- if (marginBottom !== undefined) {
18632
- style.marginBottom = marginBottom;
18633
- } else if (marginY !== undefined) {
18634
- style.marginBottom = marginY;
18635
- }
18636
- const padding = consume("padding");
18637
- const paddingX = consume("paddingX");
18638
- const paddingY = consume("paddingY");
18639
- const paddingLeft = consume("paddingLeft");
18640
- const paddingRight = consume("paddingRight");
18641
- const paddingTop = consume("paddingTop");
18642
- const paddingBottom = consume("paddingBottom");
18643
- if (padding !== undefined) {
18644
- style.padding = padding;
18645
- }
18646
- if (paddingLeft !== undefined) {
18647
- style.paddingLeft = paddingLeft;
18648
- } else if (paddingX !== undefined) {
18649
- style.paddingLeft = paddingX;
18650
- }
18651
- if (paddingRight !== undefined) {
18652
- style.paddingRight = paddingRight;
18653
- } else if (paddingX !== undefined) {
18654
- style.paddingRight = paddingX;
18655
- }
18656
- if (paddingTop !== undefined) {
18657
- style.paddingTop = paddingTop;
18658
- } else if (paddingY !== undefined) {
18659
- style.paddingTop = paddingY;
18660
- }
18661
- if (paddingBottom !== undefined) {
18662
- style.paddingBottom = paddingBottom;
18663
- } else if (paddingY !== undefined) {
18664
- style.paddingBottom = paddingY;
18600
+ {
18601
+ const margin = props.margin;
18602
+ const marginX = props.marginX;
18603
+ const marginY = props.marginY;
18604
+ const marginLeft = props.marginLeft;
18605
+ const marginRight = props.marginRight;
18606
+ const marginTop = props.marginTop;
18607
+ const marginBottom = props.marginBottom;
18608
+ delete props.margin;
18609
+ delete props.marginX;
18610
+ delete props.marginY;
18611
+ delete props.marginLeft;
18612
+ delete props.marginRight;
18613
+ delete props.marginTop;
18614
+ delete props.marginBottom;
18615
+ if (margin !== undefined) {
18616
+ style.margin = margin;
18617
+ }
18618
+ if (marginLeft !== undefined) {
18619
+ style.marginLeft = marginLeft;
18620
+ } else if (marginX !== undefined) {
18621
+ style.marginLeft = marginX;
18622
+ }
18623
+ if (marginRight !== undefined) {
18624
+ style.marginRight = marginRight;
18625
+ } else if (marginX !== undefined) {
18626
+ style.marginRight = marginX;
18627
+ }
18628
+ if (marginTop !== undefined) {
18629
+ style.marginTop = marginTop;
18630
+ } else if (marginY !== undefined) {
18631
+ style.marginTop = marginY;
18632
+ }
18633
+ if (marginBottom !== undefined) {
18634
+ style.marginBottom = marginBottom;
18635
+ } else if (marginY !== undefined) {
18636
+ style.marginBottom = marginY;
18637
+ }
18638
+ }
18639
+ {
18640
+ const padding = props.padding;
18641
+ const paddingX = props.paddingX;
18642
+ const paddingY = props.paddingY;
18643
+ const paddingLeft = props.paddingLeft;
18644
+ const paddingRight = props.paddingRight;
18645
+ const paddingTop = props.paddingTop;
18646
+ const paddingBottom = props.paddingBottom;
18647
+ delete props.padding;
18648
+ delete props.paddingX;
18649
+ delete props.paddingY;
18650
+ delete props.paddingLeft;
18651
+ delete props.paddingRight;
18652
+ delete props.paddingTop;
18653
+ delete props.paddingBottom;
18654
+ if (padding !== undefined) {
18655
+ style.padding = padding;
18656
+ }
18657
+ if (paddingLeft !== undefined) {
18658
+ style.paddingLeft = paddingLeft;
18659
+ } else if (paddingX !== undefined) {
18660
+ style.paddingLeft = paddingX;
18661
+ }
18662
+ if (paddingRight !== undefined) {
18663
+ style.paddingRight = paddingRight;
18664
+ } else if (paddingX !== undefined) {
18665
+ style.paddingRight = paddingX;
18666
+ }
18667
+ if (paddingTop !== undefined) {
18668
+ style.paddingTop = paddingTop;
18669
+ } else if (paddingY !== undefined) {
18670
+ style.paddingTop = paddingY;
18671
+ }
18672
+ if (paddingBottom !== undefined) {
18673
+ style.paddingBottom = paddingBottom;
18674
+ } else if (paddingY !== undefined) {
18675
+ style.paddingBottom = paddingY;
18676
+ }
18665
18677
  }
18666
18678
  return style;
18667
18679
  };
@@ -21352,6 +21364,153 @@ const Editable = forwardRef((props, ref) => {
21352
21364
  });
21353
21365
  });
21354
21366
 
21367
+ installImportMetaCss(import.meta);import.meta.css = /* css */`
21368
+ .navi_flex_row {
21369
+ display: flex;
21370
+ flex-direction: row;
21371
+ align-items: center;
21372
+ gap: 0;
21373
+ }
21374
+
21375
+ .navi_flex_column {
21376
+ display: flex;
21377
+ flex-direction: column;
21378
+ align-items: center;
21379
+ gap: 0;
21380
+ }
21381
+
21382
+ .navi_flex_item {
21383
+ flex-shrink: 0;
21384
+ }
21385
+ `;
21386
+ const FlexDirectionContext = createContext();
21387
+ const FlexRow = ({
21388
+ alignY,
21389
+ gap,
21390
+ style,
21391
+ children,
21392
+ ...rest
21393
+ }) => {
21394
+ const innerStyle = withPropsStyle({
21395
+ alignItems: alignY,
21396
+ gap,
21397
+ ...consumeSpacingProps(rest)
21398
+ }, style);
21399
+ return jsx("div", {
21400
+ ...rest,
21401
+ className: "navi_flex_row",
21402
+ style: innerStyle,
21403
+ children: jsx(FlexDirectionContext.Provider, {
21404
+ value: "row",
21405
+ children: children
21406
+ })
21407
+ });
21408
+ };
21409
+ const FlexColumn = ({
21410
+ alignX,
21411
+ gap,
21412
+ style,
21413
+ children,
21414
+ ...rest
21415
+ }) => {
21416
+ const innerStyle = withPropsStyle({
21417
+ alignItems: alignX,
21418
+ gap,
21419
+ ...consumeSpacingProps(rest)
21420
+ }, style);
21421
+ return jsx("div", {
21422
+ ...rest,
21423
+ className: "navi_flex_column",
21424
+ style: innerStyle,
21425
+ children: jsx(FlexDirectionContext.Provider, {
21426
+ value: "column",
21427
+ children: children
21428
+ })
21429
+ });
21430
+ };
21431
+ const useConsumAlignProps = props => {
21432
+ const flexDirection = useContext(FlexDirectionContext);
21433
+ const alignX = props.alignX;
21434
+ const alignY = props.alignY;
21435
+ delete props.alignX;
21436
+ delete props.alignY;
21437
+ const style = {};
21438
+ if (flexDirection === "row") {
21439
+ // In row direction: alignX controls justify-content, alignY controls align-self
21440
+ // Default alignY is "center" from CSS, so only set alignSelf when different
21441
+ if (alignY !== undefined && alignY !== "center") {
21442
+ style.alignSelf = alignY;
21443
+ }
21444
+ // For row, alignX uses auto margins for positioning
21445
+ // NOTE: Auto margins only work effectively for positioning individual items.
21446
+ // When multiple adjacent items have the same auto margin alignment (e.g., alignX="end"),
21447
+ // only the first item will be positioned as expected because subsequent items
21448
+ // will be positioned relative to the previous item's margins, not the container edge.
21449
+ if (alignX !== undefined) {
21450
+ if (alignX === "start") {
21451
+ style.marginRight = "auto";
21452
+ } else if (alignX === "end") {
21453
+ style.marginLeft = "auto";
21454
+ } else if (alignX === "center") {
21455
+ style.marginLeft = "auto";
21456
+ style.marginRight = "auto";
21457
+ }
21458
+ }
21459
+ } else if (flexDirection === "column") {
21460
+ // In column direction: alignX controls align-self, alignY uses auto margins
21461
+ // Default alignX is "center" from CSS, so only set alignSelf when different
21462
+ if (alignX !== undefined && alignX !== "center") {
21463
+ style.alignSelf = alignX;
21464
+ }
21465
+ // For column, alignY uses auto margins for positioning
21466
+ // NOTE: Same auto margin limitation applies - multiple adjacent items with
21467
+ // the same alignY won't all position relative to container edges.
21468
+ if (alignY !== undefined) {
21469
+ if (alignY === "start") {
21470
+ style.marginBottom = "auto";
21471
+ } else if (alignY === "end") {
21472
+ style.marginTop = "auto";
21473
+ } else if (alignY === "center") {
21474
+ style.marginTop = "auto";
21475
+ style.marginBottom = "auto";
21476
+ }
21477
+ }
21478
+ }
21479
+ return style;
21480
+ };
21481
+ const FlexItem = ({
21482
+ alignX,
21483
+ alignY,
21484
+ grow,
21485
+ shrink,
21486
+ className,
21487
+ style,
21488
+ children,
21489
+ ...rest
21490
+ }) => {
21491
+ const flexDirection = useContext(FlexDirectionContext);
21492
+ if (!flexDirection) {
21493
+ console.warn("FlexItem must be used within a FlexRow or FlexColumn component.");
21494
+ }
21495
+ const innerClassName = withPropsClassName("navi_flex_item", className);
21496
+ const alignStyle = useConsumAlignProps({
21497
+ alignX,
21498
+ alignY
21499
+ });
21500
+ const innerStyle = withPropsStyle({
21501
+ flexGrow: grow ? 1 : undefined,
21502
+ flexShrink: shrink ? 1 : undefined,
21503
+ ...consumeSpacingProps(rest),
21504
+ ...alignStyle
21505
+ }, style);
21506
+ return jsx("div", {
21507
+ ...rest,
21508
+ className: innerClassName,
21509
+ style: innerStyle,
21510
+ children: children
21511
+ });
21512
+ };
21513
+
21355
21514
  const useFormEvents = (
21356
21515
  elementRef,
21357
21516
  {
@@ -21573,7 +21732,8 @@ const ButtonBasic = forwardRef((props, ref) => {
21573
21732
  autoFocus,
21574
21733
  // visual
21575
21734
  appearance = "navi",
21576
- alignX = "start",
21735
+ alignX,
21736
+ alignY,
21577
21737
  discrete,
21578
21738
  className,
21579
21739
  style,
@@ -21599,13 +21759,9 @@ const ButtonBasic = forwardRef((props, ref) => {
21599
21759
  const innerClassName = withPropsClassName(appearance === "navi" ? "navi_button" : undefined, className);
21600
21760
  const innerStyle = withPropsStyle({
21601
21761
  ...consumeSpacingProps(rest),
21602
- ...(alignX === "start" ? {} : alignX === "center" ? {
21603
- alignSelf: "center",
21604
- marginLeft: "auto",
21605
- marginRight: "auto"
21606
- } : {
21607
- alignSelf: "end",
21608
- marginLeft: "auto"
21762
+ ...useConsumAlignProps({
21763
+ alignX,
21764
+ alignY
21609
21765
  })
21610
21766
  }, style);
21611
21767
  return jsx("button", {
@@ -22171,6 +22327,7 @@ const FormWithAction = forwardRef((props, ref) => {
22171
22327
  method,
22172
22328
  actionErrorEffect = "show_validation_message",
22173
22329
  // "show_validation_message" or "throw"
22330
+ errorMapping,
22174
22331
  onActionPrevented,
22175
22332
  onActionStart,
22176
22333
  onActionAbort,
@@ -22184,7 +22341,8 @@ const FormWithAction = forwardRef((props, ref) => {
22184
22341
  useImperativeHandle(ref, () => innerRef.current);
22185
22342
  const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
22186
22343
  const executeAction = useExecuteAction(innerRef, {
22187
- errorEffect: actionErrorEffect
22344
+ errorEffect: actionErrorEffect,
22345
+ errorMapping
22188
22346
  });
22189
22347
  const {
22190
22348
  actionPending,
@@ -28212,4 +28370,4 @@ const useDependenciesDiff = (inputs) => {
28212
28370
  return diffRef.current;
28213
28371
  };
28214
28372
 
28215
- 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 };
28373
+ export { ActionRenderer, ActiveKeyboardShortcuts, Button, Checkbox, CheckboxList, Col, Colgroup, Details, Editable, ErrorBoundaryContext, FlexColumn, FlexItem, FlexRow, 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
@@ -93,6 +93,11 @@ 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
95
  // Layout
96
+ export {
97
+ FlexColumn,
98
+ FlexItem,
99
+ FlexRow,
100
+ } from "./src/components/layout/flex.jsx";
96
101
  export { Spacing } from "./src/components/layout/spacing.jsx";
97
102
 
98
103
  // Validation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Library of components including navigation to create frontend applications",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,6 +11,7 @@ export const useExecuteAction = (
11
11
  elementRef,
12
12
  {
13
13
  errorEffect = "show_validation_message", // "show_validation_message" or "throw"
14
+ errorMapping,
14
15
  } = {},
15
16
  ) => {
16
17
  // see https://medium.com/trabe/catching-asynchronous-errors-in-react-using-error-boundaries-5e8a5fd7b971
@@ -28,7 +29,8 @@ export const useExecuteAction = (
28
29
  const validationMessageTargetRef = useRef(null);
29
30
  const addErrorMessage = (error) => {
30
31
  const validationMessageTarget = validationMessageTargetRef.current;
31
- addCustomMessage(validationMessageTarget, "action_error", error, {
32
+ const errorMapped = errorMapping ? errorMapping(error) : error;
33
+ addCustomMessage(validationMessageTarget, "action_error", errorMapped, {
32
34
  // This error should not prevent <form> submission
33
35
  // so whenever user tries to submit the form the error is cleared
34
36
  // (Hitting enter key, clicking on submit button, etc. would allow to re-submit the form in error state)
@@ -48,7 +48,7 @@ export const openCallout = (
48
48
  level = "warning",
49
49
  onClose,
50
50
  closeOnClickOutside = level === "info",
51
- hideErrorStack,
51
+ showErrorStack,
52
52
  debug = false,
53
53
  } = {},
54
54
  ) => {
@@ -116,7 +116,7 @@ export const openCallout = (
116
116
  if (Error.isError(newMessage)) {
117
117
  const error = newMessage;
118
118
  newMessage = error.message;
119
- if (!hideErrorStack && error.stack) {
119
+ if (showErrorStack && error.stack) {
120
120
  newMessage += `<pre class="navi_callout_error_stack">${escapeHtml(String(error.stack))}</pre>`;
121
121
  }
122
122
  }
@@ -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 { useConsumAlignProps } from "../layout/flex.jsx";
17
18
  import { consumeSpacingProps } from "../layout/spacing.jsx";
18
19
  import { LoaderBackground } from "../loader/loader_background.jsx";
19
20
  import { withPropsClassName } from "../props_composition/with_props_class_name.js";
@@ -211,7 +212,8 @@ const ButtonBasic = forwardRef((props, ref) => {
211
212
 
212
213
  // visual
213
214
  appearance = "navi",
214
- alignX = "start",
215
+ alignX,
216
+ alignY,
215
217
  discrete,
216
218
  className,
217
219
  style,
@@ -243,18 +245,7 @@ const ButtonBasic = forwardRef((props, ref) => {
243
245
  const innerStyle = withPropsStyle(
244
246
  {
245
247
  ...consumeSpacingProps(rest),
246
- ...(alignX === "start"
247
- ? {}
248
- : alignX === "center"
249
- ? {
250
- alignSelf: "center",
251
- marginLeft: "auto",
252
- marginRight: "auto",
253
- }
254
- : {
255
- alignSelf: "end",
256
- marginLeft: "auto",
257
- }),
248
+ ...useConsumAlignProps({ alignX, alignY }),
258
249
  },
259
250
  style,
260
251
  );
@@ -121,6 +121,7 @@ const FormWithAction = forwardRef((props, ref) => {
121
121
  action,
122
122
  method,
123
123
  actionErrorEffect = "show_validation_message", // "show_validation_message" or "throw"
124
+ errorMapping,
124
125
  onActionPrevented,
125
126
  onActionStart,
126
127
  onActionAbort,
@@ -135,6 +136,7 @@ const FormWithAction = forwardRef((props, ref) => {
135
136
  const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
136
137
  const executeAction = useExecuteAction(innerRef, {
137
138
  errorEffect: actionErrorEffect,
139
+ errorMapping,
138
140
  });
139
141
  const { actionPending, actionRequester: formActionRequester } =
140
142
  useRequestedActionStatus(innerRef);
@@ -0,0 +1,506 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Flex Layout Demo</title>
6
+ <style>
7
+ .demo-box {
8
+ min-width: 60px;
9
+ padding: 10px;
10
+ text-align: center;
11
+ background: #e3f2fd;
12
+ border: 1px solid #90caf9;
13
+ border-radius: 4px;
14
+ }
15
+ .demo-section {
16
+ margin-bottom: 30px;
17
+ padding: 20px;
18
+ background: #f8f9fa;
19
+ border-radius: 8px;
20
+ }
21
+ </style>
22
+ </head>
23
+ <body>
24
+ <div id="app"></div>
25
+ <script type="module" jsenv-type="module/jsx">
26
+ /* eslint-disable no-unused-vars */
27
+ import { render } from "preact";
28
+ import { FlexRow, FlexColumn, FlexItem, Button } from "@jsenv/navi";
29
+
30
+ const DemoBox = ({ children, ...props }) => (
31
+ <div className="demo-box" {...props}>
32
+ {children}
33
+ </div>
34
+ );
35
+
36
+ const Demo = () => {
37
+ return (
38
+ <div style={{ padding: "20px", fontFamily: "system-ui, sans-serif" }}>
39
+ <h1>Flex Layout Demo</h1>
40
+
41
+ <h2>FlexRow</h2>
42
+
43
+ <section className="demo-section">
44
+ <h3>1. Basic FlexRow</h3>
45
+ <FlexRow>
46
+ <DemoBox>Item 1</DemoBox>
47
+ <DemoBox>Item 2</DemoBox>
48
+ <DemoBox>Item 3</DemoBox>
49
+ </FlexRow>
50
+ </section>
51
+
52
+ <section className="demo-section">
53
+ <h3>2. FlexRow with Gap</h3>
54
+ <FlexRow gap="15px">
55
+ <DemoBox>Item 1</DemoBox>
56
+ <DemoBox>Item 2</DemoBox>
57
+ <DemoBox>Item 3</DemoBox>
58
+ </FlexRow>
59
+ </section>
60
+
61
+ <section className="demo-section">
62
+ <h3>3. FlexRow with Vertical Alignment</h3>
63
+
64
+ <h4>alignY="start"</h4>
65
+ <FlexRow
66
+ alignY="start"
67
+ gap="10px"
68
+ style={{
69
+ height: "80px",
70
+ background: "#fff3e0",
71
+ padding: "10px",
72
+ }}
73
+ >
74
+ <DemoBox>Short</DemoBox>
75
+ <DemoBox style={{ height: "60px", lineHeight: "60px" }}>
76
+ Tall Item
77
+ </DemoBox>
78
+ <DemoBox>Short</DemoBox>
79
+ </FlexRow>
80
+
81
+ <h4>alignY="center" (default)</h4>
82
+ <FlexRow
83
+ alignY="center"
84
+ gap="10px"
85
+ style={{
86
+ height: "80px",
87
+ background: "#e8f5e8",
88
+ padding: "10px",
89
+ }}
90
+ >
91
+ <DemoBox>Short</DemoBox>
92
+ <DemoBox style={{ height: "60px", lineHeight: "60px" }}>
93
+ Tall Item
94
+ </DemoBox>
95
+ <DemoBox>Short</DemoBox>
96
+ </FlexRow>
97
+
98
+ <h4>alignY="end"</h4>
99
+ <FlexRow
100
+ alignY="end"
101
+ gap="10px"
102
+ style={{
103
+ height: "80px",
104
+ background: "#ffebee",
105
+ padding: "10px",
106
+ }}
107
+ >
108
+ <DemoBox>Short</DemoBox>
109
+ <DemoBox style={{ height: "60px", lineHeight: "60px" }}>
110
+ Tall Item
111
+ </DemoBox>
112
+ <DemoBox>Short</DemoBox>
113
+ </FlexRow>
114
+ </section>
115
+
116
+ <h2>FlexRow + FlexItem</h2>
117
+
118
+ <section className="demo-section">
119
+ <h3>4. FlexItem Basic Usage</h3>
120
+
121
+ <FlexRow gap="10px">
122
+ <FlexItem>
123
+ <DemoBox>FlexItem 1</DemoBox>
124
+ </FlexItem>
125
+ <FlexItem>
126
+ <DemoBox>FlexItem 2</DemoBox>
127
+ </FlexItem>
128
+ <FlexItem>
129
+ <DemoBox>FlexItem 3</DemoBox>
130
+ </FlexItem>
131
+ </FlexRow>
132
+ </section>
133
+
134
+ <section className="demo-section">
135
+ <h3>5. FlexItem with Growth</h3>
136
+
137
+ <FlexRow gap="10px">
138
+ <FlexItem>
139
+ <DemoBox>Fixed</DemoBox>
140
+ </FlexItem>
141
+ <FlexItem grow>
142
+ <DemoBox>Grows to fill</DemoBox>
143
+ </FlexItem>
144
+ <FlexItem>
145
+ <DemoBox>Fixed</DemoBox>
146
+ </FlexItem>
147
+ </FlexRow>
148
+ </section>
149
+
150
+ <section className="demo-section">
151
+ <h3>6. FlexItem with alignY</h3>
152
+
153
+ <FlexRow
154
+ gap="10px"
155
+ style={{
156
+ height: "100px",
157
+ background: "#e1f5fe",
158
+ padding: "10px",
159
+ }}
160
+ >
161
+ <FlexItem>
162
+ <DemoBox>Default (center)</DemoBox>
163
+ </FlexItem>
164
+ <FlexItem alignY="start">
165
+ <DemoBox>alignY="start"</DemoBox>
166
+ </FlexItem>
167
+ <FlexItem alignY="end">
168
+ <DemoBox>alignY="end"</DemoBox>
169
+ </FlexItem>
170
+ <FlexItem alignY="stretch">
171
+ <DemoBox style={{ height: "100%" }}>alignY="stretch"</DemoBox>
172
+ </FlexItem>
173
+ </FlexRow>
174
+ </section>
175
+
176
+ <section className="demo-section">
177
+ <h3>7. FlexItem with alignX</h3>
178
+
179
+ <FlexRow
180
+ gap="10px"
181
+ style={{
182
+ background: "#f3e5f5",
183
+ padding: "10px",
184
+ }}
185
+ >
186
+ <FlexItem>
187
+ <DemoBox>Default</DemoBox>
188
+ </FlexItem>
189
+ <FlexItem alignX="start">
190
+ <DemoBox>alignX="start"</DemoBox>
191
+ </FlexItem>
192
+ <FlexItem alignX="center">
193
+ <DemoBox>alignX="center"</DemoBox>
194
+ </FlexItem>
195
+ <FlexItem alignX="end">
196
+ <DemoBox>alignX="end"</DemoBox>
197
+ </FlexItem>
198
+ </FlexRow>
199
+ </section>
200
+
201
+ <section className="demo-section">
202
+ <h3>8. Auto Margin Examples</h3>
203
+
204
+ <h4>Single item pushed to end</h4>
205
+ <FlexRow
206
+ gap="10px"
207
+ style={{ background: "#fff3e0", padding: "10px" }}
208
+ >
209
+ <DemoBox>Item 1</DemoBox>
210
+ <DemoBox>Item 2</DemoBox>
211
+ <FlexItem alignX="end">
212
+ <DemoBox>Pushed to end</DemoBox>
213
+ </FlexItem>
214
+ </FlexRow>
215
+
216
+ <h4>Single item centered</h4>
217
+ <FlexRow
218
+ gap="10px"
219
+ style={{ background: "#e8f5e8", padding: "10px" }}
220
+ >
221
+ <DemoBox>Item 1</DemoBox>
222
+ <FlexItem alignX="center">
223
+ <DemoBox>Centered</DemoBox>
224
+ </FlexItem>
225
+ <DemoBox>Item 3</DemoBox>
226
+ </FlexRow>
227
+
228
+ <h4>Multiple items pushed to end</h4>
229
+ <FlexRow
230
+ gap="10px"
231
+ style={{ background: "#f0f4ff", padding: "10px" }}
232
+ >
233
+ <DemoBox>Item 1</DemoBox>
234
+ <FlexItem alignX="end">
235
+ <DemoBox>Pushed A</DemoBox>
236
+ </FlexItem>
237
+ <FlexItem alignX="end">
238
+ <DemoBox>Pushed B</DemoBox>
239
+ </FlexItem>
240
+ <FlexItem alignX="end">
241
+ <DemoBox>Pushed C</DemoBox>
242
+ </FlexItem>
243
+ </FlexRow>
244
+
245
+ <h4>Multiple items with different alignments</h4>
246
+ <FlexRow
247
+ gap="10px"
248
+ style={{ background: "#ffebee", padding: "10px" }}
249
+ >
250
+ <FlexItem alignX="start">
251
+ <DemoBox>Start</DemoBox>
252
+ </FlexItem>
253
+ <DemoBox>Normal</DemoBox>
254
+ <FlexItem alignX="center">
255
+ <DemoBox>Center</DemoBox>
256
+ </FlexItem>
257
+ <DemoBox>Normal</DemoBox>
258
+ <FlexItem alignX="end">
259
+ <DemoBox>End</DemoBox>
260
+ </FlexItem>
261
+ </FlexRow>
262
+ </section>
263
+
264
+ <section className="demo-section">
265
+ <h3>9. Combined Growth and Alignment</h3>
266
+
267
+ <FlexRow
268
+ gap="10px"
269
+ style={{ background: "#e1f5fe", padding: "10px" }}
270
+ >
271
+ <DemoBox>Fixed</DemoBox>
272
+ <FlexItem grow>
273
+ <DemoBox>Grows</DemoBox>
274
+ </FlexItem>
275
+ <FlexItem alignX="end">
276
+ <DemoBox>Pushed to end</DemoBox>
277
+ </FlexItem>
278
+ </FlexRow>
279
+ </section>
280
+
281
+ <section className="demo-section">
282
+ <h3>10. Real-World Example: Button with alignX</h3>
283
+
284
+ <FlexRow
285
+ gap="10px"
286
+ style={{ background: "#f5f5f5", padding: "10px" }}
287
+ >
288
+ <DemoBox>Content</DemoBox>
289
+ <DemoBox>More content</DemoBox>
290
+ <Button alignX="end">Action Button</Button>
291
+ </FlexRow>
292
+ </section>
293
+
294
+ <h2>FlexColumn</h2>
295
+
296
+ <section className="demo-section">
297
+ <h3>10. Basic FlexColumn</h3>
298
+ <FlexColumn style={{ height: "200px" }}>
299
+ <DemoBox>Item 1</DemoBox>
300
+ <DemoBox>Item 2</DemoBox>
301
+ <DemoBox>Item 3</DemoBox>
302
+ </FlexColumn>
303
+ </section>
304
+
305
+ <section className="demo-section">
306
+ <h3>11. FlexColumn with Gap</h3>
307
+ <FlexColumn gap="15px" style={{ height: "200px" }}>
308
+ <DemoBox>Item 1</DemoBox>
309
+ <DemoBox>Item 2</DemoBox>
310
+ <DemoBox>Item 3</DemoBox>
311
+ </FlexColumn>
312
+ </section>
313
+
314
+ <section className="demo-section">
315
+ <h3>12. FlexColumn with Horizontal Alignment</h3>
316
+
317
+ <h4>alignX="start"</h4>
318
+ <FlexColumn
319
+ alignX="start"
320
+ gap="10px"
321
+ style={{
322
+ height: "150px",
323
+ width: "300px",
324
+ background: "#fff3e0",
325
+ padding: "10px",
326
+ }}
327
+ >
328
+ <DemoBox>Short</DemoBox>
329
+ <DemoBox style={{ width: "200px" }}>Wide Item</DemoBox>
330
+ <DemoBox>Short</DemoBox>
331
+ </FlexColumn>
332
+
333
+ <h4>alignX="center" (default)</h4>
334
+ <FlexColumn
335
+ alignX="center"
336
+ gap="10px"
337
+ style={{
338
+ height: "150px",
339
+ width: "300px",
340
+ background: "#e8f5e8",
341
+ padding: "10px",
342
+ }}
343
+ >
344
+ <DemoBox>Short</DemoBox>
345
+ <DemoBox style={{ width: "200px" }}>Wide Item</DemoBox>
346
+ <DemoBox>Short</DemoBox>
347
+ </FlexColumn>
348
+
349
+ <h4>alignX="end"</h4>
350
+ <FlexColumn
351
+ alignX="end"
352
+ gap="10px"
353
+ style={{
354
+ height: "150px",
355
+ width: "300px",
356
+ background: "#ffebee",
357
+ padding: "10px",
358
+ }}
359
+ >
360
+ <DemoBox>Short</DemoBox>
361
+ <DemoBox style={{ width: "200px" }}>Wide Item</DemoBox>
362
+ <DemoBox>Short</DemoBox>
363
+ </FlexColumn>
364
+ </section>
365
+
366
+ <section className="demo-section">
367
+ <h3>13. FlexItem with alignX in Column</h3>
368
+
369
+ <FlexColumn
370
+ gap="10px"
371
+ style={{
372
+ height: "200px",
373
+ width: "300px",
374
+ background: "#f3e5f5",
375
+ padding: "10px",
376
+ }}
377
+ >
378
+ <FlexItem>
379
+ <DemoBox>Default</DemoBox>
380
+ </FlexItem>
381
+ <FlexItem alignX="start">
382
+ <DemoBox>alignX="start"</DemoBox>
383
+ </FlexItem>
384
+ <FlexItem alignX="center">
385
+ <DemoBox>alignX="center"</DemoBox>
386
+ </FlexItem>
387
+ <FlexItem alignX="end">
388
+ <DemoBox>alignX="end"</DemoBox>
389
+ </FlexItem>
390
+ </FlexColumn>
391
+ </section>
392
+
393
+ <section className="demo-section">
394
+ <h3>14. FlexItem with alignY in Column</h3>
395
+
396
+ <FlexColumn
397
+ gap="10px"
398
+ style={{
399
+ height: "300px",
400
+ width: "200px",
401
+ background: "#e1f5fe",
402
+ padding: "10px",
403
+ }}
404
+ >
405
+ <FlexItem>
406
+ <DemoBox>Default</DemoBox>
407
+ </FlexItem>
408
+ <FlexItem alignY="start">
409
+ <DemoBox>alignY="start"</DemoBox>
410
+ </FlexItem>
411
+ <FlexItem alignY="center">
412
+ <DemoBox>alignY="center"</DemoBox>
413
+ </FlexItem>
414
+ <FlexItem alignY="end">
415
+ <DemoBox>alignY="end"</DemoBox>
416
+ </FlexItem>
417
+ </FlexColumn>
418
+ </section>
419
+
420
+ <section className="demo-section">
421
+ <h3>15. Column Auto Margin Examples</h3>
422
+
423
+ <h4>Single item pushed to bottom</h4>
424
+ <FlexColumn
425
+ gap="10px"
426
+ style={{
427
+ height: "200px",
428
+ background: "#fff3e0",
429
+ padding: "10px",
430
+ }}
431
+ >
432
+ <DemoBox>Item 1</DemoBox>
433
+ <DemoBox>Item 2</DemoBox>
434
+ <FlexItem alignY="end">
435
+ <DemoBox>Pushed to bottom</DemoBox>
436
+ </FlexItem>
437
+ </FlexColumn>
438
+
439
+ <h4>Multiple items pushed to bottom</h4>
440
+ <FlexColumn
441
+ gap="10px"
442
+ style={{
443
+ height: "250px",
444
+ background: "#f0f4ff",
445
+ padding: "10px",
446
+ }}
447
+ >
448
+ <DemoBox>Item 1</DemoBox>
449
+ <FlexItem alignY="end">
450
+ <DemoBox>Pushed A</DemoBox>
451
+ </FlexItem>
452
+ <FlexItem alignY="end">
453
+ <DemoBox>Pushed B</DemoBox>
454
+ </FlexItem>
455
+ <FlexItem alignY="end">
456
+ <DemoBox>Pushed C</DemoBox>
457
+ </FlexItem>
458
+ </FlexColumn>
459
+
460
+ <h4>Item centered vertically</h4>
461
+ <FlexColumn
462
+ gap="10px"
463
+ style={{
464
+ height: "200px",
465
+ background: "#e8f5e8",
466
+ padding: "10px",
467
+ }}
468
+ >
469
+ <DemoBox>Item 1</DemoBox>
470
+ <FlexItem alignY="center">
471
+ <DemoBox>Centered</DemoBox>
472
+ </FlexItem>
473
+ <DemoBox>Item 3</DemoBox>
474
+ </FlexColumn>
475
+ </section>
476
+
477
+ <section className="demo-section">
478
+ <h3>16. Combined Growth and Alignment in Column</h3>
479
+
480
+ <FlexColumn
481
+ gap="10px"
482
+ style={{
483
+ height: "250px",
484
+ background: "#e1f5fe",
485
+ padding: "10px",
486
+ }}
487
+ >
488
+ <DemoBox>Fixed</DemoBox>
489
+ <FlexItem grow>
490
+ <DemoBox style="height: 100%; box-sizing: border-box;">
491
+ Grows
492
+ </DemoBox>
493
+ </FlexItem>
494
+ <FlexItem alignY="end">
495
+ <DemoBox>Pushed to bottom</DemoBox>
496
+ </FlexItem>
497
+ </FlexColumn>
498
+ </section>
499
+ </div>
500
+ );
501
+ };
502
+
503
+ render(<Demo />, document.getElementById("app"));
504
+ </script>
505
+ </body>
506
+ </html>
@@ -0,0 +1,154 @@
1
+ import { createContext } from "preact";
2
+ import { useContext } from "preact/hooks";
3
+
4
+ import { withPropsClassName } from "../props_composition/with_props_class_name.js";
5
+ import { withPropsStyle } from "../props_composition/with_props_style.js";
6
+ import { consumeSpacingProps } from "./spacing.jsx";
7
+
8
+ import.meta.css = /* css */ `
9
+ .navi_flex_row {
10
+ display: flex;
11
+ flex-direction: row;
12
+ align-items: center;
13
+ gap: 0;
14
+ }
15
+
16
+ .navi_flex_column {
17
+ display: flex;
18
+ flex-direction: column;
19
+ align-items: center;
20
+ gap: 0;
21
+ }
22
+
23
+ .navi_flex_item {
24
+ flex-shrink: 0;
25
+ }
26
+ `;
27
+
28
+ const FlexDirectionContext = createContext();
29
+
30
+ export const FlexRow = ({ alignY, gap, style, children, ...rest }) => {
31
+ const innerStyle = withPropsStyle(
32
+ {
33
+ alignItems: alignY,
34
+ gap,
35
+ ...consumeSpacingProps(rest),
36
+ },
37
+ style,
38
+ );
39
+
40
+ return (
41
+ <div {...rest} className="navi_flex_row" style={innerStyle}>
42
+ <FlexDirectionContext.Provider value="row">
43
+ {children}
44
+ </FlexDirectionContext.Provider>
45
+ </div>
46
+ );
47
+ };
48
+ export const FlexColumn = ({ alignX, gap, style, children, ...rest }) => {
49
+ const innerStyle = withPropsStyle(
50
+ {
51
+ alignItems: alignX,
52
+ gap,
53
+ ...consumeSpacingProps(rest),
54
+ },
55
+ style,
56
+ );
57
+
58
+ return (
59
+ <div {...rest} className="navi_flex_column" style={innerStyle}>
60
+ <FlexDirectionContext.Provider value="column">
61
+ {children}
62
+ </FlexDirectionContext.Provider>
63
+ </div>
64
+ );
65
+ };
66
+ export const useConsumAlignProps = (props) => {
67
+ const flexDirection = useContext(FlexDirectionContext);
68
+
69
+ const alignX = props.alignX;
70
+ const alignY = props.alignY;
71
+ delete props.alignX;
72
+ delete props.alignY;
73
+
74
+ const style = {};
75
+
76
+ if (flexDirection === "row") {
77
+ // In row direction: alignX controls justify-content, alignY controls align-self
78
+ // Default alignY is "center" from CSS, so only set alignSelf when different
79
+ if (alignY !== undefined && alignY !== "center") {
80
+ style.alignSelf = alignY;
81
+ }
82
+ // For row, alignX uses auto margins for positioning
83
+ // NOTE: Auto margins only work effectively for positioning individual items.
84
+ // When multiple adjacent items have the same auto margin alignment (e.g., alignX="end"),
85
+ // only the first item will be positioned as expected because subsequent items
86
+ // will be positioned relative to the previous item's margins, not the container edge.
87
+ if (alignX !== undefined) {
88
+ if (alignX === "start") {
89
+ style.marginRight = "auto";
90
+ } else if (alignX === "end") {
91
+ style.marginLeft = "auto";
92
+ } else if (alignX === "center") {
93
+ style.marginLeft = "auto";
94
+ style.marginRight = "auto";
95
+ }
96
+ }
97
+ } else if (flexDirection === "column") {
98
+ // In column direction: alignX controls align-self, alignY uses auto margins
99
+ // Default alignX is "center" from CSS, so only set alignSelf when different
100
+ if (alignX !== undefined && alignX !== "center") {
101
+ style.alignSelf = alignX;
102
+ }
103
+ // For column, alignY uses auto margins for positioning
104
+ // NOTE: Same auto margin limitation applies - multiple adjacent items with
105
+ // the same alignY won't all position relative to container edges.
106
+ if (alignY !== undefined) {
107
+ if (alignY === "start") {
108
+ style.marginBottom = "auto";
109
+ } else if (alignY === "end") {
110
+ style.marginTop = "auto";
111
+ } else if (alignY === "center") {
112
+ style.marginTop = "auto";
113
+ style.marginBottom = "auto";
114
+ }
115
+ }
116
+ }
117
+
118
+ return style;
119
+ };
120
+ export const FlexItem = ({
121
+ alignX,
122
+ alignY,
123
+ grow,
124
+ shrink,
125
+ className,
126
+ style,
127
+ children,
128
+ ...rest
129
+ }) => {
130
+ const flexDirection = useContext(FlexDirectionContext);
131
+ if (!flexDirection) {
132
+ console.warn(
133
+ "FlexItem must be used within a FlexRow or FlexColumn component.",
134
+ );
135
+ }
136
+
137
+ const innerClassName = withPropsClassName("navi_flex_item", className);
138
+ const alignStyle = useConsumAlignProps({ alignX, alignY });
139
+ const innerStyle = withPropsStyle(
140
+ {
141
+ flexGrow: grow ? 1 : undefined,
142
+ flexShrink: shrink ? 1 : undefined,
143
+ ...consumeSpacingProps(rest),
144
+ ...alignStyle,
145
+ },
146
+ style,
147
+ );
148
+
149
+ return (
150
+ <div {...rest} className={innerClassName} style={innerStyle}>
151
+ {children}
152
+ </div>
153
+ );
154
+ };
@@ -1,77 +1,88 @@
1
1
  import { withPropsStyle } from "../props_composition/with_props_style.js";
2
2
 
3
3
  export const consumeSpacingProps = (props) => {
4
- const consume = (name) => {
5
- if (Object.hasOwn(props, name)) {
6
- const value = props[name];
7
- delete props[name];
8
- return value;
9
- }
10
- return undefined;
11
- };
12
- const margin = consume("margin");
13
- const marginX = consume("marginX");
14
- const marginY = consume("marginY");
15
- const marginLeft = consume("marginLeft");
16
- const marginRight = consume("marginRight");
17
- const marginTop = consume("marginTop");
18
- const marginBottom = consume("marginBottom");
19
-
20
4
  const style = {};
21
- if (margin !== undefined) {
22
- style.margin = margin;
23
- }
24
- if (marginLeft !== undefined) {
25
- style.marginLeft = marginLeft;
26
- } else if (marginX !== undefined) {
27
- style.marginLeft = marginX;
28
- }
29
- if (marginRight !== undefined) {
30
- style.marginRight = marginRight;
31
- } else if (marginX !== undefined) {
32
- style.marginRight = marginX;
33
- }
34
- if (marginTop !== undefined) {
35
- style.marginTop = marginTop;
36
- } else if (marginY !== undefined) {
37
- style.marginTop = marginY;
38
- }
39
- if (marginBottom !== undefined) {
40
- style.marginBottom = marginBottom;
41
- } else if (marginY !== undefined) {
42
- style.marginBottom = marginY;
43
- }
44
5
 
45
- const padding = consume("padding");
46
- const paddingX = consume("paddingX");
47
- const paddingY = consume("paddingY");
48
- const paddingLeft = consume("paddingLeft");
49
- const paddingRight = consume("paddingRight");
50
- const paddingTop = consume("paddingTop");
51
- const paddingBottom = consume("paddingBottom");
6
+ outer_spacing: {
7
+ const margin = props.margin;
8
+ const marginX = props.marginX;
9
+ const marginY = props.marginY;
10
+ const marginLeft = props.marginLeft;
11
+ const marginRight = props.marginRight;
12
+ const marginTop = props.marginTop;
13
+ const marginBottom = props.marginBottom;
14
+ delete props.margin;
15
+ delete props.marginX;
16
+ delete props.marginY;
17
+ delete props.marginLeft;
18
+ delete props.marginRight;
19
+ delete props.marginTop;
20
+ delete props.marginBottom;
52
21
 
53
- if (padding !== undefined) {
54
- style.padding = padding;
55
- }
56
- if (paddingLeft !== undefined) {
57
- style.paddingLeft = paddingLeft;
58
- } else if (paddingX !== undefined) {
59
- style.paddingLeft = paddingX;
60
- }
61
- if (paddingRight !== undefined) {
62
- style.paddingRight = paddingRight;
63
- } else if (paddingX !== undefined) {
64
- style.paddingRight = paddingX;
65
- }
66
- if (paddingTop !== undefined) {
67
- style.paddingTop = paddingTop;
68
- } else if (paddingY !== undefined) {
69
- style.paddingTop = paddingY;
22
+ if (margin !== undefined) {
23
+ style.margin = margin;
24
+ }
25
+ if (marginLeft !== undefined) {
26
+ style.marginLeft = marginLeft;
27
+ } else if (marginX !== undefined) {
28
+ style.marginLeft = marginX;
29
+ }
30
+ if (marginRight !== undefined) {
31
+ style.marginRight = marginRight;
32
+ } else if (marginX !== undefined) {
33
+ style.marginRight = marginX;
34
+ }
35
+ if (marginTop !== undefined) {
36
+ style.marginTop = marginTop;
37
+ } else if (marginY !== undefined) {
38
+ style.marginTop = marginY;
39
+ }
40
+ if (marginBottom !== undefined) {
41
+ style.marginBottom = marginBottom;
42
+ } else if (marginY !== undefined) {
43
+ style.marginBottom = marginY;
44
+ }
70
45
  }
71
- if (paddingBottom !== undefined) {
72
- style.paddingBottom = paddingBottom;
73
- } else if (paddingY !== undefined) {
74
- style.paddingBottom = paddingY;
46
+
47
+ inner_spacing: {
48
+ const padding = props.padding;
49
+ const paddingX = props.paddingX;
50
+ const paddingY = props.paddingY;
51
+ const paddingLeft = props.paddingLeft;
52
+ const paddingRight = props.paddingRight;
53
+ const paddingTop = props.paddingTop;
54
+ const paddingBottom = props.paddingBottom;
55
+ delete props.padding;
56
+ delete props.paddingX;
57
+ delete props.paddingY;
58
+ delete props.paddingLeft;
59
+ delete props.paddingRight;
60
+ delete props.paddingTop;
61
+ delete props.paddingBottom;
62
+
63
+ if (padding !== undefined) {
64
+ style.padding = padding;
65
+ }
66
+ if (paddingLeft !== undefined) {
67
+ style.paddingLeft = paddingLeft;
68
+ } else if (paddingX !== undefined) {
69
+ style.paddingLeft = paddingX;
70
+ }
71
+ if (paddingRight !== undefined) {
72
+ style.paddingRight = paddingRight;
73
+ } else if (paddingX !== undefined) {
74
+ style.paddingRight = paddingX;
75
+ }
76
+ if (paddingTop !== undefined) {
77
+ style.paddingTop = paddingTop;
78
+ } else if (paddingY !== undefined) {
79
+ style.paddingTop = paddingY;
80
+ }
81
+ if (paddingBottom !== undefined) {
82
+ style.paddingBottom = paddingBottom;
83
+ } else if (paddingY !== undefined) {
84
+ style.paddingBottom = paddingY;
85
+ }
75
86
  }
76
87
 
77
88
  return style;