@cntrl-site/components 1.0.12-alpha.2 → 1.0.12-alpha.3

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 (3) hide show
  1. package/dist/index.js +2541 -2541
  2. package/dist/index.mjs +2542 -2542
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -14953,7 +14953,7 @@ function Fd({ settings: e, content: t, isEditor: n, isPreviewMode: r, activeEven
14953
14953
  textHoverColor: ee,
14954
14954
  backgroundHoverColor: pe,
14955
14955
  dividerHoverColor: oe
14956
- } = e, [ge, N] = le(void 0), [J, q] = le(null), G = L === "On", re = (x ?? 0) > 0, W = c === "B", te = ve(null), [I, v] = le(_n), z = ji(I), U = Math.max(0, ((w ?? 0) - z) / 2), Z = Math.min(P ?? 0, U), ae = Math.max(Z, yn), se = ((w ?? 0) + z) / 2;
14956
+ } = e, [ge, N] = le(void 0), [J, q] = le(null), G = L === "On" && (!n || r), re = (x ?? 0) > 0, W = c === "B", te = ve(null), [I, v] = le(_n), z = ji(I), U = Math.max(0, ((w ?? 0) - z) / 2), Z = Math.min(P ?? 0, U), ae = Math.max(Z, yn), se = ((w ?? 0) + z) / 2;
14957
14957
  it(() => {
14958
14958
  if (!n) {
14959
14959
  v(_n);
@@ -15590,2547 +15590,2547 @@ function Fd({ settings: e, content: t, isEditor: n, isPreviewMode: r, activeEven
15590
15590
  ) })
15591
15591
  ] });
15592
15592
  }
15593
- const kd = `import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\r
15594
- import { CommonComponentProps } from '../props';\r
15595
- import { buildColorVars, scalingValue, useScopedStyles } from '../utils/index';\r
15596
- import { omitTextColors, TextStyles, textStylesToCss } from '../utils/textStylesToCss';\r
15597
- \r
15598
- type ListFontSettings = { fontWeight: number; fontStyle: string };\r
15599
- \r
15600
- type ListColumnPrefix = 'AColumn' | 'BColumn' | 'CColumn' | 'DColumn' | 'EColumn';\r
15601
- \r
15602
- type ListColumnTextStyleOverrides = {\r
15603
- AColumnVerticalAlign?: string;\r
15604
- AColumnTextFontFamily?: string;\r
15605
- AColumnTextFontSettings?: ListFontSettings;\r
15606
- AColumnTextFontSize?: number;\r
15607
- AColumnTextLineHeight?: number;\r
15608
- AColumnTextLetterSpacing?: number;\r
15609
- AColumnTextWordSpacing?: number;\r
15610
- AColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15611
- BColumnVerticalAlign?: string;\r
15612
- BColumnTextFontFamily?: string;\r
15613
- BColumnTextFontSettings?: ListFontSettings;\r
15614
- BColumnTextFontSize?: number;\r
15615
- BColumnTextLineHeight?: number;\r
15616
- BColumnTextLetterSpacing?: number;\r
15617
- BColumnTextWordSpacing?: number;\r
15618
- BColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15619
- CColumnVerticalAlign?: string;\r
15620
- CColumnTextFontFamily?: string;\r
15621
- CColumnTextFontSettings?: ListFontSettings;\r
15622
- CColumnTextFontSize?: number;\r
15623
- CColumnTextLineHeight?: number;\r
15624
- CColumnTextLetterSpacing?: number;\r
15625
- CColumnTextWordSpacing?: number;\r
15626
- CColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15627
- DColumnVerticalAlign?: string;\r
15628
- DColumnTextFontFamily?: string;\r
15629
- DColumnTextFontSettings?: ListFontSettings;\r
15630
- DColumnTextFontSize?: number;\r
15631
- DColumnTextLineHeight?: number;\r
15632
- DColumnTextLetterSpacing?: number;\r
15633
- DColumnTextWordSpacing?: number;\r
15634
- DColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15635
- EColumnVerticalAlign?: string;\r
15636
- EColumnTextFontFamily?: string;\r
15637
- EColumnTextFontSettings?: ListFontSettings;\r
15638
- EColumnTextFontSize?: number;\r
15639
- EColumnTextLineHeight?: number;\r
15640
- EColumnTextLetterSpacing?: number;\r
15641
- EColumnTextWordSpacing?: number;\r
15642
- EColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15643
- cutLabelTextFontFamily?: string;\r
15644
- cutLabelTextFontSettings?: ListFontSettings;\r
15645
- cutLabelTextFontSize?: number;\r
15646
- cutLabelTextLineHeight?: number;\r
15647
- cutLabelTextLetterSpacing?: number;\r
15648
- cutLabelTextWordSpacing?: number;\r
15649
- cutLabelTextTextAppearance?: TextStyles['textAppearance'];\r
15650
- };\r
15651
- \r
15652
- export type ListColumnVerticalAlignKey = \`\${ListColumnPrefix}VerticalAlign\`;\r
15653
- \r
15654
- type ListColumnVerticalAlignUpdates = {\r
15655
- AColumnVerticalAlign?: string;\r
15656
- BColumnVerticalAlign?: string;\r
15657
- CColumnVerticalAlign?: string;\r
15658
- DColumnVerticalAlign?: string;\r
15659
- EColumnVerticalAlign?: string;\r
15660
- };\r
15661
- \r
15662
- type ListColumnTextStyleSyncUpdates = {\r
15663
- AColumnTextFontFamily?: string;\r
15664
- AColumnTextFontSettings?: ListFontSettings;\r
15665
- AColumnTextFontSize?: number;\r
15666
- AColumnTextLineHeight?: number;\r
15667
- AColumnTextLetterSpacing?: number;\r
15668
- AColumnTextWordSpacing?: number;\r
15669
- AColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15670
- BColumnTextFontFamily?: string;\r
15671
- BColumnTextFontSettings?: ListFontSettings;\r
15672
- BColumnTextFontSize?: number;\r
15673
- BColumnTextLineHeight?: number;\r
15674
- BColumnTextLetterSpacing?: number;\r
15675
- BColumnTextWordSpacing?: number;\r
15676
- BColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15677
- CColumnTextFontFamily?: string;\r
15678
- CColumnTextFontSettings?: ListFontSettings;\r
15679
- CColumnTextFontSize?: number;\r
15680
- CColumnTextLineHeight?: number;\r
15681
- CColumnTextLetterSpacing?: number;\r
15682
- CColumnTextWordSpacing?: number;\r
15683
- CColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15684
- DColumnTextFontFamily?: string;\r
15685
- DColumnTextFontSettings?: ListFontSettings;\r
15686
- DColumnTextFontSize?: number;\r
15687
- DColumnTextLineHeight?: number;\r
15688
- DColumnTextLetterSpacing?: number;\r
15689
- DColumnTextWordSpacing?: number;\r
15690
- DColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15691
- EColumnTextFontFamily?: string;\r
15692
- EColumnTextFontSettings?: ListFontSettings;\r
15693
- EColumnTextFontSize?: number;\r
15694
- EColumnTextLineHeight?: number;\r
15695
- EColumnTextLetterSpacing?: number;\r
15696
- EColumnTextWordSpacing?: number;\r
15697
- EColumnTextTextAppearance?: TextStyles['textAppearance'];\r
15698
- cutLabelTextFontFamily?: string;\r
15699
- cutLabelTextFontSettings?: ListFontSettings;\r
15700
- cutLabelTextFontSize?: number;\r
15701
- cutLabelTextLineHeight?: number;\r
15702
- cutLabelTextLetterSpacing?: number;\r
15703
- cutLabelTextWordSpacing?: number;\r
15704
- cutLabelTextTextAppearance?: TextStyles['textAppearance'];\r
15705
- };\r
15706
- \r
15707
- export type ListSettings = {\r
15708
- columns: number;\r
15709
- type: 'A' | 'B';\r
15710
- wrapperWidth: number;\r
15711
- entriesCount: number;\r
15712
- cellMinHeight: number;\r
15713
- imageOnHover: 'On' | 'Off';\r
15714
- imageSize?: { min: number; max: number };\r
15715
- dividerWidth: number;\r
15716
- showVisibility: boolean[];\r
15717
- cut: number;\r
15718
- showCut: number;\r
15719
- cutCellMinHeight: number;\r
15720
- cutLabel: string;\r
15721
- entryHoverEffect: 'None' | 'Default' | 'Blinds';\r
15722
- rowPaddingTop: number;\r
15723
- rowPaddingBottom: number;\r
15724
- rowPaddingTopB: number;\r
15725
- AColumnWidth: number;\r
15726
- AColumnPaddingLeft: number;\r
15727
- AColumnPaddingRight: number;\r
15728
- AColumnPaddingBottom: number;\r
15729
- BColumnWidth: number;\r
15730
- BColumnPaddingLeft: number;\r
15731
- BColumnPaddingRight: number;\r
15732
- BColumnPaddingBottom: number;\r
15733
- CColumnWidth: number;\r
15734
- CColumnPaddingLeft: number;\r
15735
- CColumnPaddingRight: number;\r
15736
- CColumnPaddingBottom: number;\r
15737
- DColumnWidth: number;\r
15738
- DColumnPaddingLeft: number;\r
15739
- DColumnPaddingRight: number;\r
15740
- DColumnPaddingBottom: number;\r
15741
- EColumnWidth: number;\r
15742
- EColumnPaddingLeft: number;\r
15743
- EColumnPaddingRight: number;\r
15744
- EColumnPaddingBottom: number;\r
15745
- columnsOrder?: string[];\r
15746
- textPaddingLR?: number;\r
15747
- textColor: string;\r
15748
- textFontFamily: string;\r
15749
- textFontSettings?: ListFontSettings;\r
15750
- textFontSize?: number;\r
15751
- textLineHeight?: number;\r
15752
- textLetterSpacing?: number;\r
15753
- textWordSpacing?: number;\r
15754
- textTextAppearance?: TextStyles['textAppearance'];\r
15755
- backgroundColor: string;\r
15756
- dividerColor: string;\r
15757
- textHoverColor: string;\r
15758
- backgroundHoverColor: string;\r
15759
- dividerHoverColor: string;\r
15760
- } & ListColumnTextStyleOverrides;\r
15761
- \r
15762
- type ListContentItem = {\r
15763
- AColumn?: string;\r
15764
- BColumnWidth?: string;\r
15765
- CColumnWidth?: string;\r
15766
- DColumnWidth?: string;\r
15767
- EColumnWidth?: string;\r
15768
- image?: {\r
15769
- objectFit?: 'cover' | 'contain';\r
15770
- url: string;\r
15771
- name: string;\r
15772
- };\r
15773
- link?: string;\r
15774
- };\r
15775
- \r
15776
- type ListItemRow = {\r
15777
- id: string | number;\r
15778
- cells: Record<string, React.ReactNode>;\r
15779
- image?: ListContentItem['image'];\r
15780
- link?: string;\r
15781
- };\r
15782
- \r
15783
- type HoverImageState = {\r
15784
- rowId: string | number;\r
15785
- url: string;\r
15786
- objectFit: 'cover' | 'contain';\r
15787
- widthPx: number;\r
15788
- x: number;\r
15789
- y: number;\r
15790
- };\r
15791
- \r
15792
- type ListProps = {\r
15793
- layoutId?: string;\r
15794
- settings: ListSettings;\r
15795
- content?: ListContentItem[];\r
15796
- isEditor?: boolean;\r
15797
- isPreviewMode?: boolean;\r
15798
- activeEvent: string | undefined;\r
15799
- onUpdateSettings?: (settings: ListSettings) => void;\r
15800
- } & CommonComponentProps;\r
15801
- \r
15802
- function sv(px: number): string {\r
15803
- return \`calc(var(--cntrl-article-width, 100vw) * \${px / 1440})\`;\r
15804
- }\r
15805
- \r
15806
- function hasListColumnText(value: React.ReactNode): boolean {\r
15807
- return String(value ?? '').trim().length > 0;\r
15808
- }\r
15809
- \r
15810
- function getEntryDividerWidths(\r
15811
- rowIdx: number,\r
15812
- rowCount: number,\r
15813
- showDividerTop: boolean,\r
15814
- showDividerBottom: boolean,\r
15815
- hasCutItem: boolean,\r
15816
- dividerWidth: number,\r
15817
- isEditor: boolean,\r
15818
- ): { borderTopWidth: string; borderBottomWidth: string } {\r
15819
- const scaledDividerWidth = scalingValue(dividerWidth, isEditor);\r
15820
- const none = scalingValue(0, isEditor);\r
15821
- \r
15822
- const isFirst = rowIdx === 0;\r
15823
- const isLastEntry = rowIdx === rowCount - 1 && !hasCutItem;\r
15824
- \r
15825
- const borderTopWidth = isFirst && showDividerTop ? scaledDividerWidth : none;\r
15826
- const borderBottomWidth = !isLastEntry || showDividerBottom ? scaledDividerWidth : none;\r
15827
- \r
15828
- return { borderTopWidth, borderBottomWidth };\r
15829
- }\r
15830
- \r
15831
- function getCutItemDividerWidths(\r
15832
- showDividerBottom: boolean,\r
15833
- dividerWidth: number,\r
15834
- isEditor: boolean,\r
15835
- ): { borderTopWidth: string; borderBottomWidth: string } {\r
15836
- const scaledDividerWidth = scalingValue(dividerWidth, isEditor);\r
15837
- const none = scalingValue(0, isEditor);\r
15838
- \r
15839
- return {\r
15840
- borderTopWidth: none,\r
15841
- borderBottomWidth: showDividerBottom ? scaledDividerWidth : none,\r
15842
- };\r
15843
- }\r
15844
- \r
15845
- const HOVER_IMAGE_CURSOR_OFFSET = 10;\r
15846
- \r
15847
- function getCSS(P: string): string {\r
15848
- return \`\r
15849
- .\${P}-wrapper {\r
15850
- display: grid;\r
15851
- align-items: start;\r
15852
- min-height: \${sv(48)};\r
15853
- position: relative;\r
15854
- overflow: visible;\r
15855
- box-sizing: border-box;\r
15856
- }\r
15857
- \r
15858
- .\${P}-hover-image {\r
15859
- position: absolute;\r
15860
- left: 0;\r
15861
- top: 0;\r
15862
- z-index: 10;\r
15863
- pointer-events: none;\r
15864
- display: block;\r
15865
- height: auto;\r
15866
- }\r
15867
- \r
15868
- .\${P}-list-item {\r
15869
- display: flex;\r
15870
- flex-direction: column;\r
15871
- align-items: stretch;\r
15872
- width: 100%;\r
15873
- overflow: visible;\r
15874
- position: relative;\r
15875
- box-sizing: content-box;\r
15876
- user-select: none;\r
15877
- background: var(--\${P}-background-color);\r
15878
- }\r
15879
- \r
15880
- .\${P}-wrapper.\${P}-divider-top .\${P}-list-item {\r
15881
- border-top-style: solid;\r
15882
- border-top-color: var(--\${P}-divider-color);\r
15883
- }\r
15884
- \r
15885
- .\${P}-wrapper.\${P}-divider-bottom .\${P}-list-item {\r
15886
- border-bottom-style: solid;\r
15887
- border-bottom-color: var(--\${P}-divider-color);\r
15888
- }\r
15889
- \r
15890
- .\${P}-list-cols-row {\r
15891
- display: flex;\r
15892
- align-items: start;\r
15893
- width: 100%;\r
15894
- box-sizing: border-box;\r
15895
- }\r
15896
- \r
15897
- .\${P}-list-cols-row-h {\r
15898
- align-items: stretch;\r
15899
- }\r
15900
- \r
15901
- .\${P}-list-cols-row-h [data-list-col] {\r
15902
- display: grid;\r
15903
- grid-template-rows: minmax(0, 1fr);\r
15904
- align-self: stretch;\r
15905
- min-height: min-content;\r
15906
- }\r
15907
- \r
15908
- .\${P}-list-cols-row-h .\${P}-list-col {\r
15909
- display: flex;\r
15910
- flex-direction: column;\r
15911
- align-items: flex-start;\r
15912
- justify-content: flex-start;\r
15913
- width: 100%;\r
15914
- min-height: 0;\r
15915
- }\r
15916
- \r
15917
- .\${P}-list-cols-row-h .\${P}-list-col-title {\r
15918
- display: block;\r
15919
- flex: 0 0 auto;\r
15920
- align-self: stretch;\r
15921
- }\r
15922
- \r
15923
- .\${P}-text-tight-leading {\r
15924
- display: block;\r
15925
- flex-shrink: 0;\r
15926
- padding-top: var(--\${P}-title-leading-gap, 0);\r
15927
- padding-bottom: var(--\${P}-title-leading-gap, 0);\r
15928
- }\r
15929
- \r
15930
- .\${P}-wrapper.\${P}-type-b .\${P}-list-cols-row {\r
15931
- flex-direction: column;\r
15932
- align-items: stretch;\r
15933
- }\r
15934
- \r
15935
- .\${P}-wrapper.\${P}-type-b .\${P}-list-col {\r
15936
- width: 100%;\r
15937
- min-width: 0;\r
15938
- flex-direction: column;\r
15939
- justify-content: flex-start;\r
15940
- align-items: flex-start;\r
15941
- min-height: min-content;\r
15942
- }\r
15943
- \r
15944
- .\${P}-wrapper.\${P}-type-b .\${P}-list-col-title {\r
15945
- display: block;\r
15946
- flex: 0 0 auto;\r
15947
- align-self: stretch;\r
15948
- text-align: center;\r
15949
- }\r
15950
- \r
15951
- .\${P}-wrapper.\${P}-type-b .\${P}-cut-item .\${P}-list-cols-row {\r
15952
- flex-direction: row;\r
15953
- align-items: center;\r
15954
- justify-content: center;\r
15955
- }\r
15956
- \r
15957
- .\${P}-wrapper.\${P}-type-b .\${P}-cut-label {\r
15958
- text-align: center;\r
15959
- width: 100%;\r
15960
- box-sizing: border-box;\r
15961
- }\r
15962
- \r
15963
- .\${P}-wrapper.\${P}-type-b .\${P}-list-col-last {\r
15964
- flex: 0 0 auto;\r
15965
- min-width: 0;\r
15966
- }\r
15967
- \r
15968
- a.\${P}-list-item {\r
15969
- text-decoration: none;\r
15970
- color: inherit;\r
15971
- cursor: pointer;\r
15972
- }\r
15973
- \r
15974
- .\${P}-list-col {\r
15975
- flex-shrink: 0;\r
15976
- overflow: visible;\r
15977
- box-sizing: border-box;\r
15978
- min-width: \${sv(50)};\r
15979
- position: relative;\r
15980
- display: flex;\r
15981
- align-items: flex-start;\r
15982
- }\r
15983
- \r
15984
- .\${P}-list-col-last {\r
15985
- flex: 1 1 auto;\r
15986
- min-width: \${sv(50)};\r
15987
- }\r
15988
- \r
15989
- .\${P}-list-col-title {\r
15990
- color: var(--\${P}-text-color);\r
15991
- white-space: pre-wrap;\r
15992
- overflow-wrap: anywhere;\r
15993
- word-break: break-word;\r
15994
- flex: 1;\r
15995
- min-width: 0;\r
15996
- width: 100%;\r
15997
- box-sizing: border-box;\r
15998
- }\r
15999
- \r
16000
- .\${P}-baseline-probe {\r
16001
- display: inline-block;\r
16002
- width: 0;\r
16003
- height: 0;\r
16004
- overflow: hidden;\r
16005
- vertical-align: baseline;\r
16006
- }\r
16007
- \r
16008
- .\${P}-col-resize-handle,\r
16009
- .\${P}-padding-control-handle {\r
16010
- background: transparent;\r
16011
- }\r
16012
- \r
16013
- .\${P}-row-padding-handle {\r
16014
- position: relative;\r
16015
- z-index: 2;\r
16016
- width: 100%;\r
16017
- flex-shrink: 0;\r
16018
- background: transparent;\r
16019
- }\r
16020
- \r
16021
- .\${P}-row-padding-handle::before {\r
16022
- content: "";\r
16023
- position: absolute;\r
16024
- top: 0;\r
16025
- left: 0;\r
16026
- width: 100%;\r
16027
- height: 100%;\r
16028
- min-height: 20px;\r
16029
- pointer-events: auto;\r
16030
- z-index: 10;\r
16031
- }\r
16032
- \r
16033
- .\${P}-col-resize-handle::after {\r
16034
- content: '';\r
16035
- position: absolute;\r
16036
- top: 0;\r
16037
- left: 50%;\r
16038
- transform: translateX(-50%);\r
16039
- width: 2px;\r
16040
- height: 100%;\r
16041
- background: #FF5C02;\r
16042
- pointer-events: none;\r
16043
- }\r
16044
- \r
16045
- .\${P}-wrapper.\${P}-type-b .\${P}-col-resize-handle::after {\r
16046
- top: 50%;\r
16047
- left: 0;\r
16048
- transform: translateY(-50%);\r
16049
- width: 100%;\r
16050
- height: 2px;\r
16051
- }\r
16052
- \r
16053
- .\${P}-padding-control-handle::after {\r
16054
- content: '';\r
16055
- position: absolute;\r
16056
- top: 50%;\r
16057
- left: 50%;\r
16058
- transform: translate(-50%, -50%);\r
16059
- width: 4px;\r
16060
- height: 12px;\r
16061
- background: #FF5C02;\r
16062
- border: 1px solid #FFFFFF;\r
16063
- border-radius: 5px;\r
16064
- pointer-events: none;\r
16065
- box-sizing: border-box;\r
16066
- }\r
16067
- \r
16068
- .\${P}-wrapper.\${P}-type-b .\${P}-padding-control-handle::after {\r
16069
- width: 12px;\r
16070
- height: 4px;\r
16071
- }\r
16072
- \r
16073
- .\${P}-text-padding-lr-handle {\r
16074
- background: transparent;\r
16075
- }\r
16076
- \r
16077
- .\${P}-text-padding-lr-handle::after {\r
16078
- content: '';\r
16079
- position: absolute;\r
16080
- top: 50%;\r
16081
- left: 50%;\r
16082
- transform: translate(-50%, -50%);\r
16083
- width: 4px;\r
16084
- height: 12px;\r
16085
- background: #FF5C02;\r
16086
- border: 1px solid #FFFFFF;\r
16087
- border-radius: 5px;\r
16088
- pointer-events: none;\r
16089
- box-sizing: border-box;\r
16090
- }\r
16091
- \r
16092
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link,\r
16093
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link,\r
16094
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item,\r
16095
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item {\r
16096
- transition: background-color 250ms, border-color 250ms;\r
16097
- }\r
16098
- \r
16099
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link .\${P}-list-col-title,\r
16100
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link .\${P}-list-col-title,\r
16101
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-label,\r
16102
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-label {\r
16103
- transition: color 250ms;\r
16104
- }\r
16105
- \r
16106
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link:hover,\r
16107
- .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link,\r
16108
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item:hover,\r
16109
- .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item {\r
16110
- background: var(--\${P}-background-hover-color);\r
16111
- }\r
16112
- \r
16113
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item-has-link:hover,\r
16114
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item:has(+ .\${P}-list-item-has-link:hover),\r
16115
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item:has(+ .\${P}-cut-item:hover),\r
16116
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link,\r
16117
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-cut-item:hover,\r
16118
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item,\r
16119
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover,\r
16120
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item:has(+ .\${P}-list-item-has-link:hover),\r
16121
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item:has(+ .\${P}-cut-item:hover),\r
16122
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link,\r
16123
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-cut-item:hover,\r
16124
- .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item {\r
16125
- border-bottom-color: var(--\${P}-divider-hover-color);\r
16126
- }\r
16127
- \r
16128
- .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-default .\${P}-list-item-has-link:hover:first-child,\r
16129
- .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link:first-child,\r
16130
- .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover:first-child,\r
16131
- .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link:first-child {\r
16132
- border-top-color: var(--\${P}-divider-hover-color);\r
16133
- }\r
16134
- \r
16135
- .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item-has-link:hover:first-child,\r
16136
- .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link:first-child,\r
16137
- .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover:first-child,\r
16138
- .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link:first-child {\r
16139
- border-top-color: var(--\${P}-divider-hover-color);\r
16140
- }\r
16141
- \r
16142
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link:hover .\${P}-list-col-title,\r
16143
- .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link .\${P}-list-col-title,\r
16144
- .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item:hover .\${P}-cut-label,\r
16145
- .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item .\${P}-cut-label,\r
16146
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover .\${P}-list-col-title,\r
16147
- .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link .\${P}-list-col-title,\r
16148
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item:hover .\${P}-cut-label,\r
16149
- .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item .\${P}-cut-label {\r
16150
- color: var(--\${P}-text-hover-color);\r
16151
- }\r
16152
- \r
16153
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link::before,\r
16154
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item::before {\r
16155
- content: '';\r
16156
- position: absolute;\r
16157
- inset: 0;\r
16158
- background: var(--\${P}-background-hover-color);\r
16159
- transform: scaleY(0);\r
16160
- transform-origin: center center;\r
16161
- transition: transform 250ms;\r
16162
- z-index: 0;\r
16163
- pointer-events: none;\r
16164
- }\r
16165
- \r
16166
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-col,\r
16167
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-label {\r
16168
- position: relative;\r
16169
- z-index: 1;\r
16170
- }\r
16171
- \r
16172
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover::before,\r
16173
- .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link::before,\r
16174
- .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item:hover::before,\r
16175
- .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item::before {\r
16176
- transform: scaleY(1);\r
16177
- }\r
16178
- \r
16179
- .\${P}-cut-item {\r
16180
- display: flex;\r
16181
- align-items: center;\r
16182
- justify-content: center;\r
16183
- width: 100%;\r
16184
- overflow: visible;\r
16185
- position: relative;\r
16186
- z-index: 3;\r
16187
- box-sizing: border-box;\r
16188
- user-select: none;\r
16189
- background: var(--\${P}-background-color);\r
16190
- cursor: pointer;\r
16191
- padding: 0;\r
16192
- border: none;\r
16193
- font: inherit;\r
16194
- text-align: inherit;\r
16195
- appearance: none;\r
16196
- -webkit-appearance: none;\r
16197
- }\r
16198
- \r
16199
- .\${P}-cut-item .\${P}-list-cols-row {\r
16200
- flex: 1;\r
16201
- min-height: 100%;\r
16202
- align-items: center;\r
16203
- }\r
16204
- \r
16205
- .\${P}-wrapper.\${P}-divider-bottom .\${P}-cut-item {\r
16206
- border-bottom-style: solid;\r
16207
- border-bottom-color: var(--\${P}-divider-color);\r
16208
- }\r
16209
- \r
16210
- .\${P}-cut-label {\r
16211
- display: block;\r
16212
- position: relative;\r
16213
- z-index: 1;\r
16214
- margin: 0;\r
16215
- color: var(--\${P}-text-color);\r
16216
- white-space: pre-wrap;\r
16217
- overflow-wrap: anywhere;\r
16218
- word-break: break-word;\r
16219
- }\r
16220
- \`;\r
16221
- }\r
16222
- \r
16223
- export const COLUMN_CONTENT_KEYS = [\r
16224
- 'AColumn',\r
16225
- 'BColumnWidth',\r
16226
- 'CColumnWidth',\r
16227
- 'DColumnWidth',\r
16228
- 'EColumnWidth',\r
16229
- ] as const;\r
16230
- \r
16231
- export const COLUMN_TEXT_PREFIXES = [\r
16232
- 'AColumn',\r
16233
- 'BColumn',\r
16234
- 'CColumn',\r
16235
- 'DColumn',\r
16236
- 'EColumn',\r
16237
- ] as const;\r
16238
- \r
16239
- export const CUT_LABEL_TEXT_PREFIX = 'cutLabel' as const;\r
16240
- \r
16241
- export const LIST_TEXT_STYLE_PREFIXES = [\r
16242
- ...COLUMN_TEXT_PREFIXES,\r
16243
- CUT_LABEL_TEXT_PREFIX,\r
16244
- ] as const;\r
16245
- \r
16246
- export type ListTextStylePrefix = typeof LIST_TEXT_STYLE_PREFIXES[number];\r
16247
- \r
16248
- export const LIST_COLUMN_LETTERS = ['A', 'B', 'C', 'D', 'E'] as const;\r
16249
- \r
16250
- export function getListColumnVerticalAlignSettingKey(columnLetter: string): string {\r
16251
- return \`\${columnLetter}ColumnVerticalAlign\`;\r
16252
- }\r
16253
- \r
16254
- export const COLUMN_VALIGN_BASIC_OPTIONS = ['Top', 'Center', 'Bottom'] as const;\r
16255
- \r
16256
- export function isBaselineAnchorColumnVerticalAlign(value: string | undefined): boolean {\r
16257
- const raw = String(value ?? 'Top').trim();\r
16258
- if (raw.toLowerCase().startsWith('baseline')) {\r
16259
- return false;\r
16260
- }\r
16261
- return raw === 'Top' || raw === 'Center' || raw === 'Bottom';\r
16262
- }\r
16263
- \r
16264
- export function parseBaselineAnchorLetter(value: string | undefined): string | null {\r
16265
- const raw = String(value ?? '').trim();\r
16266
- if (!raw.toLowerCase().startsWith('baseline')) {\r
16267
- return null;\r
16268
- }\r
16269
- const anchorLetter = raw.slice(-1).toUpperCase();\r
16270
- return LIST_COLUMN_LETTERS.includes(anchorLetter as typeof LIST_COLUMN_LETTERS[number])\r
16271
- ? anchorLetter\r
16272
- : null;\r
16273
- }\r
16274
- \r
16275
- export function isValidColumnBaselineVAlign(\r
16276
- value: string | undefined,\r
16277
- forColumnLetter: string,\r
16278
- settings: ListSettings,\r
16279
- ): boolean {\r
16280
- const anchorLetter = parseBaselineAnchorLetter(value);\r
16281
- if (!anchorLetter) {\r
16282
- return true;\r
16283
- }\r
16284
- if (anchorLetter === forColumnLetter) {\r
16285
- return false;\r
16286
- }\r
16287
- return isBaselineAnchorColumnVerticalAlign(settings[getListColumnVerticalAlignSettingKey(anchorLetter) as ListColumnVerticalAlignKey]);\r
16288
- }\r
16289
- \r
16290
- export function getColumnVerticalAlignOptionsForLetter(\r
16291
- columnLetter: string,\r
16292
- settings: ListSettings,\r
16293
- ): string[] {\r
16294
- const baselineOptions = LIST_COLUMN_LETTERS\r
16295
- .filter((letter) => letter !== columnLetter)\r
16296
- .filter((letter) => isBaselineAnchorColumnVerticalAlign(settings[getListColumnVerticalAlignSettingKey(letter) as ListColumnVerticalAlignKey]))\r
16297
- .map((letter) => \`Baseline \${letter}\`);\r
16298
- \r
16299
- return [...COLUMN_VALIGN_BASIC_OPTIONS, ...baselineOptions];\r
16300
- }\r
16301
- \r
16302
- type ColumnVerticalAlign =\r
16303
- | { kind: 'top' | 'center' | 'bottom' }\r
16304
- | { kind: 'baseline'; anchorLetter: string };\r
16305
- \r
16306
- function parseColumnVerticalAlign(value: string | undefined): ColumnVerticalAlign {\r
16307
- const raw = String(value ?? 'Top').trim();\r
16308
- if (raw.toLowerCase().startsWith('baseline')) {\r
16309
- const anchorLetter = raw.slice(-1).toUpperCase();\r
16310
- if (LIST_COLUMN_LETTERS.includes(anchorLetter as typeof LIST_COLUMN_LETTERS[number])) {\r
16311
- return { kind: 'baseline', anchorLetter };\r
16312
- }\r
16313
- return { kind: 'top' };\r
16314
- }\r
16315
- if (raw === 'Center') return { kind: 'center' };\r
16316
- if (raw === 'Bottom') return { kind: 'bottom' };\r
16317
- return { kind: 'top' };\r
16318
- }\r
16319
- \r
16320
- function resolveColumnVerticalAlign(\r
16321
- value: string | undefined,\r
16322
- settings: ListSettings,\r
16323
- columnLetter: string,\r
16324
- ): ColumnVerticalAlign {\r
16325
- if (isActiveBaselineVAlign(value, settings, columnLetter)) {\r
16326
- return parseColumnVerticalAlign(value);\r
16327
- }\r
16328
- \r
16329
- const parsed = parseColumnVerticalAlign(value);\r
16330
- if (parsed.kind === 'baseline') {\r
16331
- return { kind: 'top' };\r
16332
- }\r
16333
- \r
16334
- return parsed;\r
16335
- }\r
16336
- \r
16337
- function isActiveBaselineVAlign(\r
16338
- value: string | undefined,\r
16339
- settings: ListSettings,\r
16340
- forColumnLetter: string,\r
16341
- ): boolean {\r
16342
- if (!isValidColumnBaselineVAlign(value, forColumnLetter, settings)) {\r
16343
- return false;\r
16344
- }\r
16345
- return parseColumnVerticalAlign(value).kind === 'baseline';\r
16346
- }\r
16347
- \r
16348
- function getListColumnVerticalAlignSanitizeUpdates(\r
16349
- settings: ListSettings,\r
16350
- ): ListColumnVerticalAlignUpdates | null {\r
16351
- if (settings.type === 'B') {\r
16352
- return null;\r
16353
- }\r
16354
- \r
16355
- const updates: ListColumnVerticalAlignUpdates = {};\r
16356
- let hasUpdates = false;\r
16357
- \r
16358
- for (const letter of LIST_COLUMN_LETTERS) {\r
16359
- const key = getListColumnVerticalAlignSettingKey(letter) as ListColumnVerticalAlignKey;\r
16360
- const value = settings[key];\r
16361
- if (!isValidColumnBaselineVAlign(value, letter, settings)) {\r
16362
- updates[key] = 'Top';\r
16363
- hasUpdates = true;\r
16364
- }\r
16365
- }\r
16366
- \r
16367
- return hasUpdates ? updates : null;\r
16368
- }\r
16369
- \r
16370
- function vAlignToTitleStyle(\r
16371
- kind: ColumnVerticalAlign['kind'],\r
16372
- ): React.CSSProperties {\r
16373
- if (kind === 'center') {\r
16374
- return { marginTop: 'auto', marginBottom: 'auto' };\r
16375
- }\r
16376
- if (kind === 'bottom') {\r
16377
- return { marginTop: 'auto' };\r
16378
- }\r
16379
- return {};\r
16380
- }\r
16381
- \r
16382
- function getFirstLineBaselineOffsetInTitle(\r
16383
- titleEl: HTMLElement,\r
16384
- probeClassName: string,\r
16385
- ): number {\r
16386
- const probe = document.createElement('i');\r
16387
- probe.className = probeClassName;\r
16388
- probe.setAttribute('aria-hidden', 'true');\r
16389
- titleEl.prepend(probe);\r
16390
- \r
16391
- const { top: titleTop } = titleEl.getBoundingClientRect();\r
16392
- const { bottom: probeBottom } = probe.getBoundingClientRect();\r
16393
- const baselineOffset = probeBottom - titleTop;\r
16394
- probe.remove();\r
16395
- \r
16396
- return baselineOffset;\r
16397
- }\r
16398
- \r
16399
- function measureColumnFirstLineBaselineOffset(\r
16400
- info: {\r
16401
- titleEl: HTMLElement | null;\r
16402
- kind: string;\r
16403
- },\r
16404
- rowTop: number,\r
16405
- listColClassName: string,\r
16406
- probeClassName: string,\r
16407
- ): number {\r
16408
- const titleEl = info.titleEl;\r
16409
- if (!titleEl) return 0;\r
16410
- \r
16411
- const listCol = titleEl.closest<HTMLElement>(\`.\${listColClassName}\`);\r
16412
- if (!listCol) return 0;\r
16413
- \r
16414
- const baselineInTitle = getFirstLineBaselineOffsetInTitle(titleEl, probeClassName);\r
16415
- \r
16416
- if (info.kind === 'baseline') {\r
16417
- return titleEl.getBoundingClientRect().top - rowTop + baselineInTitle;\r
16418
- }\r
16419
- \r
16420
- const listColRect = listCol.getBoundingClientRect();\r
16421
- const titleHeight = titleEl.getBoundingClientRect().height;\r
16422
- let valignOffset = 0;\r
16423
- \r
16424
- if (info.kind === 'center') {\r
16425
- valignOffset = (listColRect.height - titleHeight) / 2;\r
16426
- } else if (info.kind === 'bottom') {\r
16427
- valignOffset = listColRect.height - titleHeight;\r
16428
- }\r
16429
- \r
16430
- return (listColRect.top - rowTop) + valignOffset + baselineInTitle;\r
16431
- }\r
16432
- \r
16433
- function syncRowListColHeights(\r
16434
- rowEl: HTMLElement,\r
16435
- cols: HTMLElement[],\r
16436
- listColClassName: string,\r
16437
- ): number {\r
16438
- const rowHeight = rowEl.getBoundingClientRect().height;\r
16439
- if (rowHeight <= 0) {\r
16440
- return 0;\r
16441
- }\r
16442
- \r
16443
- cols.forEach((colEl) => {\r
16444
- const listCol = colEl.querySelector<HTMLElement>(\`.\${listColClassName}\`);\r
16445
- if (listCol) {\r
16446
- listCol.style.minHeight = \`\${rowHeight}px\`;\r
16447
- listCol.style.height = \`\${rowHeight}px\`;\r
16448
- }\r
16449
- });\r
16450
- \r
16451
- void rowEl.offsetHeight;\r
16452
- return rowHeight;\r
16453
- }\r
16454
- \r
16455
- function applyBaselineTitleShift(titleEl: HTMLElement | null, shift: number): number {\r
16456
- if (!titleEl || !shift) {\r
16457
- if (titleEl) {\r
16458
- titleEl.style.transform = '';\r
16459
- }\r
16460
- return 0;\r
16461
- }\r
16462
- \r
16463
- titleEl.style.transform = \`translateY(\${shift}px)\`;\r
16464
- return shift;\r
16465
- }\r
16466
- \r
16467
- const COLUMN_CONTENT_KEY_TO_TEXT_PREFIX: Record<\r
16468
- typeof COLUMN_CONTENT_KEYS[number],\r
16469
- typeof COLUMN_TEXT_PREFIXES[number]\r
16470
- > = {\r
16471
- AColumn: 'AColumn',\r
16472
- BColumnWidth: 'BColumn',\r
16473
- CColumnWidth: 'CColumn',\r
16474
- DColumnWidth: 'DColumn',\r
16475
- EColumnWidth: 'EColumn',\r
16476
- };\r
16477
- \r
16478
- export const LIST_GLOBAL_TEXT_STYLE_KEYS = [\r
16479
- 'textFontFamily',\r
16480
- 'textFontSettings',\r
16481
- 'textFontSize',\r
16482
- 'textLineHeight',\r
16483
- 'textLetterSpacing',\r
16484
- 'textWordSpacing',\r
16485
- 'textTextAppearance',\r
16486
- ] as const;\r
16487
- \r
16488
- export type ListGlobalTextStyleKey = typeof LIST_GLOBAL_TEXT_STYLE_KEYS[number];\r
16489
- \r
16490
- export function getListColumnTextSettingKey(\r
16491
- prefix: ListTextStylePrefix,\r
16492
- globalKey: ListGlobalTextStyleKey,\r
16493
- ): string {\r
16494
- return \`\${prefix}\${globalKey.replace(/^text/, 'Text')}\`;\r
16495
- }\r
16496
- \r
16497
- type ListTextStyleFields = {\r
16498
- textFontFamily?: string;\r
16499
- textFontSettings?: { fontWeight: number; fontStyle: string };\r
16500
- textFontSize?: number;\r
16501
- textLineHeight?: number;\r
16502
- textLetterSpacing?: number;\r
16503
- textWordSpacing?: number;\r
16504
- textTextAppearance?: TextStyles['textAppearance'];\r
16505
- textColor?: string;\r
16506
- };\r
16507
- \r
16508
- type ResolvedListTextFields = {\r
16509
- textFontFamily: string;\r
16510
- textFontSettings: { fontWeight: number; fontStyle: string };\r
16511
- textFontSize?: number;\r
16512
- textLineHeight?: number;\r
16513
- textLetterSpacing: number;\r
16514
- textWordSpacing: number;\r
16515
- textTextAppearance?: TextStyles['textAppearance'];\r
16516
- textColor?: string;\r
16517
- };\r
16518
- \r
16519
- function resolveListGlobalTextFields(\r
16520
- settings: ListTextStyleFields,\r
16521
- ): ResolvedListTextFields {\r
16522
- return {\r
16523
- textFontFamily: settings.textFontFamily ?? 'Arial',\r
16524
- textFontSettings: settings.textFontSettings ?? {\r
16525
- fontWeight: 400,\r
16526
- fontStyle: 'normal',\r
16527
- },\r
16528
- textFontSize: settings.textFontSize,\r
16529
- textLineHeight: settings.textLineHeight,\r
16530
- textLetterSpacing: settings.textLetterSpacing ?? 0,\r
16531
- textWordSpacing: settings.textWordSpacing ?? 0,\r
16532
- textTextAppearance: settings.textTextAppearance,\r
16533
- textColor: settings.textColor,\r
16534
- };\r
16535
- }\r
16536
- \r
16537
- function resolveListColumnTextFields(\r
16538
- settings: ListSettings,\r
16539
- textPrefix: ListTextStylePrefix,\r
16540
- ): ResolvedListTextFields {\r
16541
- const read = <K extends ListGlobalTextStyleKey>(globalKey: K) => {\r
16542
- const columnKey = getListColumnTextSettingKey(textPrefix, globalKey);\r
16543
- const columnValue = settings[columnKey as keyof ListSettings];\r
16544
- if (columnValue !== undefined) {\r
16545
- return columnValue as ListTextStyleFields[K];\r
16546
- }\r
16547
- return settings[globalKey];\r
16548
- };\r
16549
- \r
16550
- return {\r
16551
- textFontFamily: (read('textFontFamily') as string | undefined) ?? 'Arial',\r
16552
- textFontSettings: (read('textFontSettings') as ListTextStyleFields['textFontSettings']) ?? {\r
16553
- fontWeight: 400,\r
16554
- fontStyle: 'normal',\r
16555
- },\r
16556
- textFontSize: read('textFontSize') as number | undefined,\r
16557
- textLineHeight: read('textLineHeight') as number | undefined,\r
16558
- textLetterSpacing: (read('textLetterSpacing') as number | undefined) ?? 0,\r
16559
- textWordSpacing: (read('textWordSpacing') as number | undefined) ?? 0,\r
16560
- textTextAppearance: read('textTextAppearance') as ListTextStyleFields['textTextAppearance'],\r
16561
- textColor: settings.textColor,\r
16562
- };\r
16563
- }\r
16564
- \r
16565
- function listColumnTextFieldsToCss(\r
16566
- fields: ResolvedListTextFields,\r
16567
- isEditor?: boolean,\r
16568
- ): React.CSSProperties {\r
16569
- const resolvedTextStyle: TextStyles = {\r
16570
- fontSettings: {\r
16571
- fontFamily: fields.textFontFamily,\r
16572
- fontWeight: fields.textFontSettings?.fontWeight ?? 400,\r
16573
- fontStyle: fields.textFontSettings?.fontStyle ?? 'normal',\r
16574
- },\r
16575
- fontSize: fields.textFontSize ?? 0.01,\r
16576
- lineHeight: fields.textLineHeight,\r
16577
- letterSpacing: fields.textLetterSpacing,\r
16578
- wordSpacing: fields.textWordSpacing,\r
16579
- textAppearance: fields.textTextAppearance,\r
16580
- color: fields.textColor ?? '#767676',\r
16581
- };\r
16582
- \r
16583
- return omitTextColors(textStylesToCss(resolvedTextStyle, isEditor));\r
16584
- }\r
16585
- \r
16586
- function getListColumnTitleClassName(\r
16587
- settings: ListSettings,\r
16588
- prefix: ListTextStylePrefix,\r
16589
- baseClassName: string,\r
16590
- tightLeadingClassName: string,\r
16591
- ): string {\r
16592
- const fields = resolveListColumnTextFields(settings, prefix);\r
16593
- const fontSize = fields.textFontSize ?? 0.01;\r
16594
- const lineHeight = fields.textLineHeight;\r
16595
- const needsTightLeading = lineHeight !== undefined && lineHeight < fontSize;\r
16596
- \r
16597
- return needsTightLeading\r
16598
- ? \`\${baseClassName} \${tightLeadingClassName}\`\r
16599
- : baseClassName;\r
16600
- }\r
16601
- \r
16602
- function getListColumnTitleVars(\r
16603
- settings: ListSettings,\r
16604
- prefix: ListTextStylePrefix,\r
16605
- titleVarPrefix: string,\r
16606
- isEditor?: boolean,\r
16607
- ): React.CSSProperties {\r
16608
- const fields = resolveListColumnTextFields(settings, prefix);\r
16609
- const fontSize = fields.textFontSize ?? 0.01;\r
16610
- const lineHeight = fields.textLineHeight;\r
16611
- \r
16612
- if (lineHeight === undefined || lineHeight >= fontSize) {\r
16613
- return {};\r
16614
- }\r
16615
- \r
16616
- return {\r
16617
- [\`--\${titleVarPrefix}-title-leading-gap\`]: scalingValue((fontSize - lineHeight) / 2, isEditor),\r
16618
- } as React.CSSProperties;\r
16619
- }\r
16620
- \r
16621
- function getListGlobalTextSyncUpdates(\r
16622
- nextSettings: ListSettings,\r
16623
- prevSettings: ListSettings,\r
16624
- ): ListColumnTextStyleSyncUpdates | null {\r
16625
- const updates: ListColumnTextStyleSyncUpdates = {};\r
16626
- let hasChanges = false;\r
16627
- \r
16628
- for (const globalKey of LIST_GLOBAL_TEXT_STYLE_KEYS) {\r
16629
- if (nextSettings[globalKey] === prevSettings[globalKey]) {\r
16630
- continue;\r
16631
- }\r
16632
- if (nextSettings[globalKey] === undefined) {\r
16633
- continue;\r
16634
- }\r
16635
- \r
16636
- hasChanges = true;\r
16637
- for (const prefix of LIST_TEXT_STYLE_PREFIXES) {\r
16638
- Object.assign(updates, {\r
16639
- [getListColumnTextSettingKey(prefix, globalKey)]: nextSettings[globalKey],\r
16640
- });\r
16641
- }\r
16642
- }\r
16643
- \r
16644
- return hasChanges ? updates : null;\r
16645
- }\r
16646
- \r
16647
- const COLUMN_WIDTH_KEYS = [\r
16648
- 'AColumnWidth',\r
16649
- 'BColumnWidth',\r
16650
- 'CColumnWidth',\r
16651
- 'DColumnWidth',\r
16652
- 'EColumnWidth',\r
16653
- ] as const;\r
16654
- \r
16655
- const COLUMN_PADDING_LEFT_KEYS = [\r
16656
- 'AColumnPaddingLeft',\r
16657
- 'BColumnPaddingLeft',\r
16658
- 'CColumnPaddingLeft',\r
16659
- 'DColumnPaddingLeft',\r
16660
- 'EColumnPaddingLeft',\r
16661
- ] as const;\r
16662
- \r
16663
- const COLUMN_PADDING_RIGHT_KEYS = [\r
16664
- 'AColumnPaddingRight',\r
16665
- 'BColumnPaddingRight',\r
16666
- 'CColumnPaddingRight',\r
16667
- 'DColumnPaddingRight',\r
16668
- 'EColumnPaddingRight',\r
16669
- ] as const;\r
16670
- \r
16671
- const COLUMN_PADDING_BOTTOM_KEYS = [\r
16672
- 'AColumnPaddingBottom',\r
16673
- 'BColumnPaddingBottom',\r
16674
- 'CColumnPaddingBottom',\r
16675
- 'DColumnPaddingBottom',\r
16676
- 'EColumnPaddingBottom',\r
16677
- ] as const;\r
16678
- \r
16679
- type ColumnWidthKey = typeof COLUMN_WIDTH_KEYS[number];\r
16680
- type ColumnPaddingLeftKey = typeof COLUMN_PADDING_LEFT_KEYS[number];\r
16681
- type ColumnPaddingRightKey = typeof COLUMN_PADDING_RIGHT_KEYS[number];\r
16682
- type ColumnPaddingBottomKey = typeof COLUMN_PADDING_BOTTOM_KEYS[number];\r
16683
- \r
16684
- type ListColumnPaddingUpdates = {\r
16685
- AColumnPaddingLeft?: number;\r
16686
- AColumnPaddingRight?: number;\r
16687
- BColumnPaddingLeft?: number;\r
16688
- BColumnPaddingRight?: number;\r
16689
- CColumnPaddingLeft?: number;\r
16690
- CColumnPaddingRight?: number;\r
16691
- DColumnPaddingLeft?: number;\r
16692
- DColumnPaddingRight?: number;\r
16693
- EColumnPaddingLeft?: number;\r
16694
- EColumnPaddingRight?: number;\r
16695
- };\r
16696
- \r
16697
- type ListColumnWidthUpdates = {\r
16698
- AColumnWidth?: number;\r
16699
- BColumnWidth?: number;\r
16700
- CColumnWidth?: number;\r
16701
- DColumnWidth?: number;\r
16702
- EColumnWidth?: number;\r
16703
- };\r
16704
- \r
16705
- type ListItemColumn = {\r
16706
- key: string;\r
16707
- textPrefix: typeof COLUMN_TEXT_PREFIXES[number];\r
16708
- widthKey: ColumnWidthKey;\r
16709
- paddingLeftKey: ColumnPaddingLeftKey;\r
16710
- paddingRightKey: ColumnPaddingRightKey;\r
16711
- paddingBottomKey: ColumnPaddingBottomKey;\r
16712
- width: number;\r
16713
- paddingLeft: number;\r
16714
- paddingRight: number;\r
16715
- paddingBottom: number;\r
16716
- };\r
16717
- \r
16718
- type ColorKeys =\r
16719
- | 'textColor'\r
16720
- | 'backgroundColor'\r
16721
- | 'dividerColor'\r
16722
- | 'textHoverColor'\r
16723
- | 'backgroundHoverColor'\r
16724
- | 'dividerHoverColor';\r
16725
- \r
16726
- const COLOR_VAR_MAP: Record<ColorKeys, string> = {\r
16727
- textColor: 'text-color',\r
16728
- backgroundColor: 'background-color',\r
16729
- dividerColor: 'divider-color',\r
16730
- textHoverColor: 'text-hover-color',\r
16731
- backgroundHoverColor: 'background-hover-color',\r
16732
- dividerHoverColor: 'divider-hover-color',\r
16733
- };\r
16734
- \r
16735
- const STATE_KEYS = ['hover', 'focus', 'filled', 'success', 'error'] as const;\r
16736
- \r
16737
- const COL_RESIZE_HANDLE_WIDTH = 0.004;\r
16738
- const COL_PADDING_HANDLE_WIDTH = 0.004;\r
16739
- const MIN_COLUMN_WIDTH_PX = 50;\r
16740
- const ARTICLE_DESIGN_WIDTH = 1440;\r
16741
- const MIN_COLUMN_WIDTH = MIN_COLUMN_WIDTH_PX / ARTICLE_DESIGN_WIDTH;\r
16742
- \r
16743
- export function getListMinColumnWidth(designWidthPx?: number): number {\r
16744
- const designWidth = typeof designWidthPx === 'number' && designWidthPx > 0\r
16745
- ? designWidthPx\r
16746
- : ARTICLE_DESIGN_WIDTH;\r
16747
- \r
16748
- return MIN_COLUMN_WIDTH_PX / designWidth;\r
16749
- }\r
16750
- \r
16751
- function getEditorDesignWidth(element: HTMLElement | null | undefined): number {\r
16752
- let el = element ?? null;\r
16753
- \r
16754
- while (el) {\r
16755
- const inline = el.style.getPropertyValue('--cntrl-article-width').trim();\r
16756
- if (inline) {\r
16757
- const px = parseFloat(inline);\r
16758
- if (Number.isFinite(px) && px > 0) {\r
16759
- return px;\r
16760
- }\r
16761
- }\r
16762
- \r
16763
- const computed = getComputedStyle(el).getPropertyValue('--cntrl-article-width').trim();\r
16764
- if (computed) {\r
16765
- const px = parseFloat(computed);\r
16766
- if (Number.isFinite(px) && px > 0) {\r
16767
- return px;\r
16768
- }\r
16769
- }\r
16770
- \r
16771
- el = el.parentElement;\r
16772
- }\r
16773
- \r
16774
- return ARTICLE_DESIGN_WIDTH;\r
16775
- }\r
16776
- \r
16777
- const DEFAULT_COLUMN_WIDTHS: Record<ColumnWidthKey, number> = {\r
16778
- AColumnWidth: 0.02,\r
16779
- BColumnWidth: 0.02,\r
16780
- CColumnWidth: 0.02,\r
16781
- DColumnWidth: 0.02,\r
16782
- EColumnWidth: 0.02,\r
16783
- };\r
16784
- \r
16785
- export function getListEffectiveContentWidth(\r
16786
- settings: ListSettings,\r
16787
- ): number {\r
16788
- const wrapperWidth = typeof settings.wrapperWidth === 'number' ? settings.wrapperWidth : 1;\r
16789
- \r
16790
- return Math.max(0, wrapperWidth);\r
16791
- }\r
16792
- \r
16793
- export function getEqualListColumnWidthUpdates(\r
16794
- columns: number,\r
16795
- contentWidth: number = 1,\r
16796
- ): Record<ColumnWidthKey, number> {\r
16797
- const equalColumnWidth = contentWidth / columns;\r
16798
- return Object.fromEntries(\r
16799
- COLUMN_WIDTH_KEYS.map((key) => [key, equalColumnWidth]),\r
16800
- ) as Record<ColumnWidthKey, number>;\r
16801
- }\r
16802
- \r
16803
- function getResetListColumnPaddingUpdates(): Record<\r
16804
- ColumnPaddingLeftKey | ColumnPaddingRightKey,\r
16805
- number\r
16806
- > {\r
16807
- return Object.fromEntries([\r
16808
- ...COLUMN_PADDING_LEFT_KEYS.map((key) => [key, 0]),\r
16809
- ...COLUMN_PADDING_RIGHT_KEYS.map((key) => [key, 0]),\r
16810
- ]) as Record<ColumnPaddingLeftKey | ColumnPaddingRightKey, number>;\r
16811
- }\r
16812
- \r
16813
- function getResetListColumnPaddingBottomUpdates(): Record<ColumnPaddingBottomKey, number> {\r
16814
- return Object.fromEntries(\r
16815
- COLUMN_PADDING_BOTTOM_KEYS.map((key) => [key, 0]),\r
16816
- ) as Record<ColumnPaddingBottomKey, number>;\r
16817
- }\r
16818
- \r
16819
- function getStoredColumnWidths(\r
16820
- settings: ListSettings,\r
16821
- ): Record<ColumnWidthKey, number> {\r
16822
- return Object.fromEntries(\r
16823
- COLUMN_WIDTH_KEYS.map((key) => [\r
16824
- key,\r
16825
- typeof settings[key] === 'number'\r
16826
- ? settings[key] as number\r
16827
- : DEFAULT_COLUMN_WIDTHS[key],\r
16828
- ]),\r
16829
- ) as Record<ColumnWidthKey, number>;\r
16830
- }\r
16831
- \r
16832
- export function resolveListColumnPadding(\r
16833
- columnWidth: number,\r
16834
- paddingLeft: number,\r
16835
- paddingRight: number,\r
16836
- ): { paddingLeft: number; paddingRight: number } {\r
16837
- const maxTotalPadding = columnWidth - MIN_COLUMN_WIDTH;\r
16838
- const totalPadding = paddingLeft + paddingRight;\r
16839
- \r
16840
- if (totalPadding <= 0 || totalPadding <= maxTotalPadding) {\r
16841
- return { paddingLeft, paddingRight };\r
16842
- }\r
16843
- \r
16844
- if (maxTotalPadding <= 0) {\r
16845
- return { paddingLeft: 0, paddingRight: 0 };\r
16846
- }\r
16847
- \r
16848
- const scale = maxTotalPadding / totalPadding;\r
16849
- \r
16850
- return {\r
16851
- paddingLeft: paddingLeft * scale,\r
16852
- paddingRight: paddingRight * scale,\r
16853
- };\r
16854
- }\r
16855
- \r
16856
- export function getEffectiveListColumnWidths(\r
16857
- columns: number,\r
16858
- wrapperWidth: number,\r
16859
- storedWidths: Record<ColumnWidthKey, number>,\r
16860
- ): number[] {\r
16861
- const resolvedWidths = resolveListColumnWidths(columns, wrapperWidth, storedWidths);\r
16862
- \r
16863
- if (columns <= 0) {\r
16864
- return [];\r
16865
- }\r
16866
- \r
16867
- const sumFixed = resolvedWidths.slice(0, columns - 1).reduce((sum, width) => sum + width, 0);\r
16868
- \r
16869
- return [\r
16870
- ...resolvedWidths.slice(0, columns - 1),\r
16871
- Math.max(0, wrapperWidth - sumFixed),\r
16872
- ];\r
16873
- }\r
16874
- \r
16875
- function getListColumnPaddingUpdates(\r
16876
- columns: number,\r
16877
- effectiveWidths: number[],\r
16878
- settings: ListSettings,\r
16879
- ): ListColumnPaddingUpdates {\r
16880
- const updates: ListColumnPaddingUpdates = {};\r
16881
- \r
16882
- for (let index = 0; index < columns; index += 1) {\r
16883
- const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];\r
16884
- const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];\r
16885
- const storedPaddingLeft = typeof settings[paddingLeftKey] === 'number'\r
16886
- ? settings[paddingLeftKey] as number\r
16887
- : 0;\r
16888
- const storedPaddingRight = typeof settings[paddingRightKey] === 'number'\r
16889
- ? settings[paddingRightKey] as number\r
16890
- : 0;\r
16891
- const resolvedPadding = resolveListColumnPadding(\r
16892
- effectiveWidths[index] ?? 0,\r
16893
- storedPaddingLeft,\r
16894
- storedPaddingRight,\r
16895
- );\r
16896
- \r
16897
- if (resolvedPadding.paddingLeft !== storedPaddingLeft) {\r
16898
- updates[paddingLeftKey] = resolvedPadding.paddingLeft;\r
16899
- }\r
16900
- \r
16901
- if (resolvedPadding.paddingRight !== storedPaddingRight) {\r
16902
- updates[paddingRightKey] = resolvedPadding.paddingRight;\r
16903
- }\r
16904
- }\r
16905
- \r
16906
- return updates;\r
16907
- }\r
16908
- \r
16909
- export function resolveListColumnWidths(\r
16910
- columns: number,\r
16911
- wrapperWidth: number,\r
16912
- storedWidths: Record<ColumnWidthKey, number>,\r
16913
- ): number[] {\r
16914
- if (columns <= 0) {\r
16915
- return [];\r
16916
- }\r
16917
- \r
16918
- const widths = COLUMN_WIDTH_KEYS.slice(0, columns).map(\r
16919
- (key) => storedWidths[key],\r
16920
- );\r
16921
- \r
16922
- if (columns === 1) {\r
16923
- return widths;\r
16924
- }\r
16925
- \r
16926
- const fixedWidths = widths.slice(0, columns - 1);\r
16927
- const fixedSum = fixedWidths.reduce((sum, width) => sum + width, 0);\r
16928
- const minTotalWidth = fixedSum + MIN_COLUMN_WIDTH;\r
16929
- \r
16930
- if (wrapperWidth >= minTotalWidth) {\r
16931
- return widths;\r
16932
- }\r
16933
- \r
16934
- const resolvedFixedWidths = [...fixedWidths];\r
16935
- let overflow = minTotalWidth - wrapperWidth;\r
16936
- \r
16937
- for (let index = resolvedFixedWidths.length - 1; index >= 0 && overflow > 0; index -= 1) {\r
16938
- const shrinkable = resolvedFixedWidths[index] - MIN_COLUMN_WIDTH;\r
16939
- if (shrinkable <= 0) {\r
16940
- continue;\r
16941
- }\r
16942
- \r
16943
- const shrinkAmount = Math.min(overflow, shrinkable);\r
16944
- resolvedFixedWidths[index] -= shrinkAmount;\r
16945
- overflow -= shrinkAmount;\r
16946
- }\r
16947
- \r
16948
- return [...resolvedFixedWidths, widths[columns - 1]];\r
16949
- }\r
16950
- \r
16951
- function getListColumnWidthUpdatesForWrapperWidth(\r
16952
- columns: number,\r
16953
- wrapperWidth: number,\r
16954
- storedWidths: Record<ColumnWidthKey, number>,\r
16955
- ): ListColumnWidthUpdates {\r
16956
- if (columns <= 1) {\r
16957
- return {};\r
16958
- }\r
16959
- \r
16960
- const resolvedWidths = resolveListColumnWidths(columns, wrapperWidth, storedWidths);\r
16961
- const updates: ListColumnWidthUpdates = {};\r
16962
- \r
16963
- for (let index = 0; index < columns - 1; index += 1) {\r
16964
- const key = COLUMN_WIDTH_KEYS[index];\r
16965
- if (resolvedWidths[index] !== storedWidths[key]) {\r
16966
- updates[key] = resolvedWidths[index];\r
16967
- }\r
16968
- }\r
16969
- \r
16970
- return updates;\r
16971
- }\r
16972
- \r
16973
- function getColumnsOrder(settings: ListSettings): string[] {\r
16974
- if (Array.isArray(settings.columnsOrder) && settings.columnsOrder.length > 0) {\r
16975
- return settings.columnsOrder as string[];\r
16976
- }\r
16977
- \r
16978
- return [...COLUMN_CONTENT_KEYS];\r
16979
- }\r
16980
- \r
16981
- function areStringArraysEqual(left: string[], right: string[]): boolean {\r
16982
- if (left.length !== right.length) {\r
16983
- return false;\r
16984
- }\r
16985
- \r
16986
- return left.every((value, index) => value === right[index]);\r
16987
- }\r
16988
- \r
16989
- function getColumnLayoutUpdatesForOrderChange(\r
16990
- nextOrder: string[],\r
16991
- prevOrder: string[],\r
16992
- prevSettings: ListSettings,\r
16993
- columns: number,\r
16994
- ): Record<string, number> {\r
16995
- const count = Math.min(columns, nextOrder.length, COLUMN_WIDTH_KEYS.length);\r
16996
- const updates: Record<string, number> = {};\r
16997
- \r
16998
- for (let index = 0; index < count; index += 1) {\r
16999
- const contentKey = nextOrder[index];\r
17000
- const prevSlotIndex = prevOrder.indexOf(contentKey);\r
17001
- \r
17002
- if (prevSlotIndex === -1) {\r
17003
- continue;\r
17004
- }\r
17005
- \r
17006
- const prevWidthKey = COLUMN_WIDTH_KEYS[prevSlotIndex];\r
17007
- const prevPaddingLeftKey = COLUMN_PADDING_LEFT_KEYS[prevSlotIndex];\r
17008
- const prevPaddingRightKey = COLUMN_PADDING_RIGHT_KEYS[prevSlotIndex];\r
17009
- const prevPaddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[prevSlotIndex];\r
17010
- const widthKey = COLUMN_WIDTH_KEYS[index];\r
17011
- const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];\r
17012
- const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];\r
17013
- const paddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[index];\r
17014
- \r
17015
- const prevWidth = prevSettings[prevWidthKey];\r
17016
- const prevPaddingLeft = prevSettings[prevPaddingLeftKey];\r
17017
- const prevPaddingRight = prevSettings[prevPaddingRightKey];\r
17018
- const prevPaddingBottom = prevSettings[prevPaddingBottomKey];\r
17019
- \r
17020
- if (typeof prevWidth === 'number') {\r
17021
- updates[widthKey] = prevWidth;\r
17022
- }\r
17023
- \r
17024
- if (typeof prevPaddingLeft === 'number') {\r
17025
- updates[paddingLeftKey] = prevPaddingLeft;\r
17026
- }\r
17027
- \r
17028
- if (typeof prevPaddingRight === 'number') {\r
17029
- updates[paddingRightKey] = prevPaddingRight;\r
17030
- }\r
17031
- \r
17032
- if (typeof prevPaddingBottom === 'number') {\r
17033
- updates[paddingBottomKey] = prevPaddingBottom;\r
17034
- }\r
17035
- }\r
17036
- \r
17037
- return updates;\r
17038
- }\r
17039
- \r
17040
- export function applyListSettingsChange(\r
17041
- nextSettings: ListSettings,\r
17042
- prevSettings: ListSettings,\r
17043
- options?: { designWidth?: number },\r
17044
- ): ListSettings {\r
17045
- const textSyncUpdates = getListGlobalTextSyncUpdates(nextSettings, prevSettings);\r
17046
- if (textSyncUpdates) {\r
17047
- nextSettings = { ...nextSettings, ...textSyncUpdates };\r
17048
- }\r
17049
- \r
17050
- const valignSanitizeUpdates = getListColumnVerticalAlignSanitizeUpdates(nextSettings);\r
17051
- if (valignSanitizeUpdates) {\r
17052
- nextSettings = { ...nextSettings, ...valignSanitizeUpdates };\r
17053
- }\r
17054
- \r
17055
- const minColumnWidth = getListMinColumnWidth(options?.designWidth);\r
17056
- const nextColumns = nextSettings.columns;\r
17057
- const prevColumns = prevSettings.columns;\r
17058
- const nextContentWidth = getListEffectiveContentWidth(nextSettings);\r
17059
- const prevContentWidth = getListEffectiveContentWidth(prevSettings);\r
17060
- const isVerticalLayout = nextSettings.type === 'B'\r
17061
- || (nextSettings.type === undefined && prevSettings.type === 'B');\r
17062
- const columns =\r
17063
- typeof nextColumns === 'number'\r
17064
- ? nextColumns\r
17065
- : typeof prevColumns === 'number'\r
17066
- ? prevColumns\r
17067
- : COLUMN_CONTENT_KEYS.length;\r
17068
- \r
17069
- const withColumnPaddingUpdates = (\r
17070
- settings: ListSettings,\r
17071
- ): ListSettings => {\r
17072
- if (isVerticalLayout) {\r
17073
- return settings;\r
17074
- }\r
17075
- \r
17076
- const storedWidths = getStoredColumnWidths({ ...prevSettings, ...settings });\r
17077
- const contentWidth = getListEffectiveContentWidth(settings);\r
17078
- const effectiveWidths = getEffectiveListColumnWidths(columns, contentWidth, storedWidths);\r
17079
- const paddingUpdates = getListColumnPaddingUpdates(columns, effectiveWidths, {\r
17080
- ...prevSettings,\r
17081
- ...settings,\r
17082
- });\r
17083
- \r
17084
- if (Object.keys(paddingUpdates).length === 0) {\r
17085
- return settings;\r
17086
- }\r
17087
- \r
17088
- return {\r
17089
- ...settings,\r
17090
- ...paddingUpdates,\r
17091
- };\r
17092
- };\r
17093
- \r
17094
- if (typeof nextColumns === 'number' && nextColumns !== prevColumns) {\r
17095
- const updates: ListSettings = {\r
17096
- ...nextSettings,\r
17097
- ...getEqualListColumnWidthUpdates(nextColumns, nextContentWidth),\r
17098
- ...getResetListColumnPaddingUpdates(),\r
17099
- };\r
17100
- \r
17101
- if (isVerticalLayout) {\r
17102
- for (const key of COLUMN_PADDING_BOTTOM_KEYS) {\r
17103
- if (typeof prevSettings[key] === 'number') {\r
17104
- updates[key] = prevSettings[key];\r
17105
- }\r
17106
- }\r
17107
- } else {\r
17108
- Object.assign(updates, getResetListColumnPaddingBottomUpdates());\r
17109
- }\r
17110
- \r
17111
- return updates;\r
17112
- }\r
17113
- \r
17114
- const nextOrder = getColumnsOrder(nextSettings);\r
17115
- const prevOrder = getColumnsOrder(prevSettings);\r
17116
- \r
17117
- if (!areStringArraysEqual(nextOrder, prevOrder)) {\r
17118
- return withColumnPaddingUpdates({\r
17119
- ...nextSettings,\r
17120
- ...getColumnLayoutUpdatesForOrderChange(nextOrder, prevOrder, prevSettings, columns),\r
17121
- });\r
17122
- }\r
17123
- \r
17124
- if (nextContentWidth < prevContentWidth) {\r
17125
- if (typeof columns === 'number' && !isVerticalLayout) {\r
17126
- const storedWidths = getStoredColumnWidths({ ...prevSettings, ...nextSettings });\r
17127
- \r
17128
- return withColumnPaddingUpdates({\r
17129
- ...nextSettings,\r
17130
- ...getListColumnWidthUpdatesForWrapperWidth(columns, nextContentWidth, storedWidths),\r
17131
- });\r
17132
- }\r
17133
- }\r
17134
- \r
17135
- if (isVerticalLayout) {\r
17136
- const storedTextPaddingLR = typeof nextSettings.textPaddingLR === 'number'\r
17137
- ? nextSettings.textPaddingLR as number\r
17138
- : 0;\r
17139
- const maxAllowedPadding = Math.max(0, (nextContentWidth - minColumnWidth) / 2);\r
17140
- \r
17141
- if (storedTextPaddingLR > maxAllowedPadding) {\r
17142
- return { ...nextSettings, textPaddingLR: maxAllowedPadding };\r
17143
- }\r
17144
- \r
17145
- return nextSettings;\r
17146
- }\r
17147
- \r
17148
- const storedWidths = getStoredColumnWidths({ ...prevSettings, ...nextSettings });\r
17149
- const prevEffectiveWidths = getEffectiveListColumnWidths(\r
17150
- columns,\r
17151
- prevContentWidth,\r
17152
- getStoredColumnWidths(prevSettings),\r
17153
- );\r
17154
- const nextEffectiveWidths = getEffectiveListColumnWidths(\r
17155
- columns,\r
17156
- nextContentWidth,\r
17157
- storedWidths,\r
17158
- );\r
17159
- const columnWidthDecreased = nextEffectiveWidths.some(\r
17160
- (width, index) => width < (prevEffectiveWidths[index] ?? width),\r
17161
- );\r
17162
- const columnWidthSettingChanged = COLUMN_WIDTH_KEYS.some((key) => {\r
17163
- const nextWidth = nextSettings[key];\r
17164
- const prevWidth = prevSettings[key];\r
17165
- \r
17166
- return typeof nextWidth === 'number'\r
17167
- && typeof prevWidth === 'number'\r
17168
- && nextWidth !== prevWidth;\r
17169
- });\r
17170
- \r
17171
- if (columnWidthDecreased || columnWidthSettingChanged) {\r
17172
- return withColumnPaddingUpdates(nextSettings);\r
17173
- }\r
17174
- \r
17175
- return nextSettings;\r
17176
- }\r
17177
- \r
17178
- function getColumnMaxWidth(\r
17179
- columnIndex: number,\r
17180
- resolvedWidths: number[],\r
17181
- storedWidths: number[],\r
17182
- wrapperWidth: number,\r
17183
- ): number {\r
17184
- const leftWidth = resolvedWidths\r
17185
- .slice(0, columnIndex)\r
17186
- .reduce((sum, width) => sum + width, 0);\r
17187
- const rightPreferredWidth = storedWidths\r
17188
- .slice(columnIndex + 1, resolvedWidths.length - 1)\r
17189
- .reduce((sum, width) => sum + width, 0);\r
17190
- \r
17191
- return Math.max(\r
17192
- MIN_COLUMN_WIDTH,\r
17193
- wrapperWidth - leftWidth - rightPreferredWidth - MIN_COLUMN_WIDTH,\r
17194
- );\r
17195
- }\r
17196
- \r
17197
- function randomBetween(min: number, max: number): number {\r
17198
- return Math.random() * (max - min) + min;\r
17199
- }\r
17200
- \r
17201
- function getColumnWidthsFromSettings(\r
17202
- settings: ListSettings,\r
17203
- ): Record<ColumnWidthKey, number> {\r
17204
- return Object.fromEntries(\r
17205
- COLUMN_WIDTH_KEYS.map((key) => [\r
17206
- key,\r
17207
- typeof settings[key] === 'number' ? settings[key] as number : DEFAULT_COLUMN_WIDTHS[key],\r
17208
- ]),\r
17209
- ) as Record<ColumnWidthKey, number>;\r
17210
- }\r
17211
- \r
17212
- function getNumericSettingValues<K extends ColumnPaddingLeftKey | ColumnPaddingRightKey | ColumnPaddingBottomKey>(\r
17213
- settings: ListSettings,\r
17214
- keys: readonly K[],\r
17215
- fallback = 0,\r
17216
- ): Record<K, number> {\r
17217
- return Object.fromEntries(\r
17218
- keys.map((key) => [\r
17219
- key,\r
17220
- typeof settings[key] === 'number' ? settings[key] as number : fallback,\r
17221
- ]),\r
17222
- ) as Record<K, number>;\r
17223
- }\r
17224
- \r
17225
- function buildListColumns(\r
17226
- columnContentOrder: readonly typeof COLUMN_CONTENT_KEYS[number][],\r
17227
- columns: number,\r
17228
- columnWidthByKey: Record<ColumnWidthKey, number>,\r
17229
- columnPaddingLeftByKey: Record<ColumnPaddingLeftKey, number>,\r
17230
- columnPaddingRightByKey: Record<ColumnPaddingRightKey, number>,\r
17231
- columnPaddingBottomByKey: Record<ColumnPaddingBottomKey, number>,\r
17232
- ): ListItemColumn[] {\r
17233
- return columnContentOrder.slice(0, columns).map((key, index) => {\r
17234
- const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];\r
17235
- const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];\r
17236
- const paddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[index];\r
17237
- \r
17238
- return {\r
17239
- key,\r
17240
- textPrefix: COLUMN_CONTENT_KEY_TO_TEXT_PREFIX[key],\r
17241
- widthKey: COLUMN_WIDTH_KEYS[index],\r
17242
- width: columnWidthByKey[COLUMN_WIDTH_KEYS[index]],\r
17243
- paddingLeftKey,\r
17244
- paddingRightKey,\r
17245
- paddingBottomKey,\r
17246
- paddingLeft: columnPaddingLeftByKey[paddingLeftKey],\r
17247
- paddingRight: columnPaddingRightByKey[paddingRightKey],\r
17248
- paddingBottom: columnPaddingBottomByKey[paddingBottomKey],\r
17249
- };\r
17250
- });\r
17251
- }\r
17252
- \r
17253
- export function List({ settings, content, isEditor, isPreviewMode, activeEvent, layoutId, onUpdateSettings }: ListProps) {\r
17254
- const { prefix: P } = useScopedStyles();\r
17255
- const showControls = Boolean(isEditor && isPreviewMode);\r
17256
- const {\r
17257
- columns,\r
17258
- type,\r
17259
- wrapperWidth,\r
17260
- entriesCount,\r
17261
- cellMinHeight,\r
17262
- dividerWidth,\r
17263
- showVisibility,\r
17264
- cut,\r
17265
- showCut,\r
17266
- cutCellMinHeight,\r
17267
- cutLabel,\r
17268
- imageSize,\r
17269
- imageOnHover,\r
17270
- entryHoverEffect,\r
17271
- rowPaddingTop,\r
17272
- rowPaddingBottom,\r
17273
- rowPaddingTopB,\r
17274
- columnsOrder,\r
17275
- textPaddingLR,\r
17276
- textColor,\r
17277
- textFontFamily,\r
17278
- textFontSettings,\r
17279
- textFontSize,\r
17280
- textLineHeight,\r
17281
- textLetterSpacing,\r
17282
- textWordSpacing,\r
17283
- textTextAppearance,\r
17284
- backgroundColor,\r
17285
- dividerColor,\r
17286
- textHoverColor,\r
17287
- backgroundHoverColor,\r
17288
- dividerHoverColor,\r
17289
- } = settings;\r
17290
- \r
17291
- const [visibleRowCount, setVisibleRowCount] = useState<number | undefined>(undefined);\r
17292
- const [hoverImage, setHoverImage] = useState<HoverImageState | null>(null);\r
17293
- const showHoverImage = imageOnHover === 'On';\r
17294
- const cutEnabled = (cut ?? 0) > 0;\r
17295
- const isVerticalLayout = type === 'B';\r
17296
- const containerRef = useRef<HTMLDivElement>(null);\r
17297
- const [designWidth, setDesignWidth] = useState(ARTICLE_DESIGN_WIDTH);\r
17298
- const minColumnWidth = getListMinColumnWidth(designWidth);\r
17299
- \r
17300
- const storedTextPaddingLRMax = Math.max(0, ((wrapperWidth ?? 0) - minColumnWidth) / 2);\r
17301
- const effectiveTextPaddingLR = Math.min(textPaddingLR ?? 0, storedTextPaddingLRMax);\r
17302
- const textPaddingLRHandleWidth = Math.max(effectiveTextPaddingLR, COL_PADDING_HANDLE_WIDTH);\r
17303
- const textPaddingLRMaxFraction = ((wrapperWidth ?? 0) + minColumnWidth) / 2;\r
17304
- \r
17305
- useLayoutEffect(() => {\r
17306
- if (!isEditor) {\r
17307
- setDesignWidth(ARTICLE_DESIGN_WIDTH);\r
17308
- return;\r
17309
- }\r
17310
- \r
17311
- const syncDesignWidth = () => {\r
17312
- setDesignWidth(getEditorDesignWidth(containerRef.current));\r
17313
- };\r
17314
- \r
17315
- syncDesignWidth();\r
17316
- \r
17317
- const observed = containerRef.current;\r
17318
- if (!observed) {\r
17319
- return;\r
17320
- }\r
17321
- \r
17322
- const observer = new ResizeObserver(syncDesignWidth);\r
17323
- observer.observe(observed);\r
17324
- \r
17325
- let pageEl: HTMLElement | null = observed;\r
17326
- while (pageEl && !pageEl.style.getPropertyValue('--cntrl-article-width')) {\r
17327
- pageEl = pageEl.parentElement;\r
17328
- }\r
17329
- if (pageEl) {\r
17330
- observer.observe(pageEl);\r
17331
- }\r
17332
- \r
17333
- return () => observer.disconnect();\r
17334
- }, [isEditor, layoutId]);\r
17335
- \r
17336
- useEffect(() => {\r
17337
- setVisibleRowCount(undefined);\r
17338
- }, [cut, showCut, content, entriesCount]);\r
17339
- \r
17340
- const colorVars = buildColorVars(P, {\r
17341
- textColor,\r
17342
- backgroundColor,\r
17343
- dividerColor,\r
17344
- textHoverColor,\r
17345
- backgroundHoverColor,\r
17346
- dividerHoverColor\r
17347
- }, COLOR_VAR_MAP, STATE_KEYS);\r
17348
- \r
17349
- const stateClass = activeEvent && activeEvent !== 'default' ? \`\${P}-state-\${activeEvent}\` : '';\r
17350
- const entryHoverClass =\r
17351
- entryHoverEffect === 'Default'\r
17352
- ? \`\${P}-entry-hover-default\`\r
17353
- : entryHoverEffect === 'Blinds'\r
17354
- ? \`\${P}-entry-hover-blinds\`\r
17355
- : '';\r
17356
- const wrapperStateClasses = \`\${entryHoverClass} \${stateClass}\`.trim();\r
17357
- const showDividerTop = showVisibility?.[0] ?? false;\r
17358
- const showDividerBottom = showVisibility?.[1] ?? false;\r
17359
- \r
17360
- const prevSettingsRef = useRef(settings);\r
17361
- const prevLayoutIdRef = useRef(layoutId);\r
17362
- \r
17363
- useEffect(() => {\r
17364
- if (!onUpdateSettings || !isEditor) {\r
17365
- prevSettingsRef.current = settings;\r
17366
- prevLayoutIdRef.current = layoutId;\r
17367
- return;\r
17368
- }\r
17369
- \r
17370
- if (prevLayoutIdRef.current !== layoutId) {\r
17371
- prevSettingsRef.current = settings;\r
17372
- prevLayoutIdRef.current = layoutId;\r
17373
- return;\r
17374
- }\r
17375
- \r
17376
- const prevSettings = prevSettingsRef.current;\r
17377
- const updatedSettings = applyListSettingsChange(\r
17378
- settings,\r
17379
- prevSettings,\r
17380
- { designWidth },\r
17381
- );\r
17382
- \r
17383
- prevSettingsRef.current = settings;\r
17384
- \r
17385
- if (updatedSettings === settings) {\r
17386
- return;\r
17387
- }\r
17388
- \r
17389
- onUpdateSettings(updatedSettings);\r
17390
- }, [settings, onUpdateSettings, isEditor, layoutId, designWidth]);\r
17391
- \r
17392
- const columnWidthByKey = useMemo(\r
17393
- () => getColumnWidthsFromSettings(settings),\r
17394
- [\r
17395
- settings.AColumnWidth,\r
17396
- settings.BColumnWidth,\r
17397
- settings.CColumnWidth,\r
17398
- settings.DColumnWidth,\r
17399
- settings.EColumnWidth,\r
17400
- ],\r
17401
- );\r
17402
- \r
17403
- const columnPaddingLeftByKey = useMemo(\r
17404
- () => getNumericSettingValues(settings, COLUMN_PADDING_LEFT_KEYS),\r
17405
- [\r
17406
- settings.AColumnPaddingLeft,\r
17407
- settings.BColumnPaddingLeft,\r
17408
- settings.CColumnPaddingLeft,\r
17409
- settings.DColumnPaddingLeft,\r
17410
- settings.EColumnPaddingLeft,\r
17411
- ],\r
17412
- );\r
17413
- \r
17414
- const columnPaddingRightByKey = useMemo(\r
17415
- () => getNumericSettingValues(settings, COLUMN_PADDING_RIGHT_KEYS),\r
17416
- [\r
17417
- settings.AColumnPaddingRight,\r
17418
- settings.BColumnPaddingRight,\r
17419
- settings.CColumnPaddingRight,\r
17420
- settings.DColumnPaddingRight,\r
17421
- settings.EColumnPaddingRight,\r
17422
- ],\r
17423
- );\r
17424
- \r
17425
- const columnPaddingBottomByKey = useMemo(\r
17426
- () => getNumericSettingValues(settings, COLUMN_PADDING_BOTTOM_KEYS),\r
17427
- [\r
17428
- settings.AColumnPaddingBottom,\r
17429
- settings.BColumnPaddingBottom,\r
17430
- settings.CColumnPaddingBottom,\r
17431
- settings.DColumnPaddingBottom,\r
17432
- settings.EColumnPaddingBottom,\r
17433
- ],\r
17434
- );\r
17435
- \r
17436
- const columnContentOrder = useMemo((): typeof COLUMN_CONTENT_KEYS[number][] => {\r
17437
- if (Array.isArray(columnsOrder) && columnsOrder.length > 0) {\r
17438
- return columnsOrder as typeof COLUMN_CONTENT_KEYS[number][];\r
17439
- }\r
17440
- return [...COLUMN_CONTENT_KEYS];\r
17441
- }, [columnsOrder]);\r
17442
- \r
17443
- const listColumns = useMemo(\r
17444
- () => buildListColumns(\r
17445
- columnContentOrder,\r
17446
- columns,\r
17447
- columnWidthByKey,\r
17448
- columnPaddingLeftByKey,\r
17449
- columnPaddingRightByKey,\r
17450
- columnPaddingBottomByKey,\r
17451
- ),\r
17452
- [columnContentOrder, columns, columnWidthByKey, columnPaddingLeftByKey, columnPaddingRightByKey, columnPaddingBottomByKey],\r
17453
- );\r
17454
- \r
17455
- const resolvedContentWidth = getListEffectiveContentWidth(settings);\r
17456
- \r
17457
- const storedColumnWidths = useMemo(\r
17458
- () => COLUMN_WIDTH_KEYS.slice(0, columns).map((key) => columnWidthByKey[key]),\r
17459
- [columns, columnWidthByKey],\r
17460
- );\r
17461
- \r
17462
- const resolvedColumnWidths = useMemo(\r
17463
- () => resolveListColumnWidths(columns, resolvedContentWidth, columnWidthByKey),\r
17464
- [columns, resolvedContentWidth, columnWidthByKey],\r
17465
- );\r
17466
- \r
17467
- const effectiveColumnWidths = useMemo(\r
17468
- () => getEffectiveListColumnWidths(columns, resolvedContentWidth, columnWidthByKey),\r
17469
- [columns, resolvedContentWidth, columnWidthByKey],\r
17470
- );\r
17471
- \r
17472
- const effectiveColumnPaddings = useMemo(\r
17473
- () =>\r
17474
- listColumns.map((col, index) =>\r
17475
- resolveListColumnPadding(\r
17476
- effectiveColumnWidths[index] ?? 0,\r
17477
- col.paddingLeft,\r
17478
- col.paddingRight,\r
17479
- )),\r
17480
- [listColumns, effectiveColumnWidths],\r
17481
- );\r
17482
- \r
17483
- const allRows: ListItemRow[] = useMemo(() => {\r
17484
- const resEntriesCount = entriesCount === 0 ? Infinity : entriesCount;\r
17485
- const items = (content ?? []).slice(0, resEntriesCount);\r
17486
- \r
17487
- return items.map((item, index) => ({\r
17488
- id: index,\r
17489
- cells: Object.fromEntries(\r
17490
- COLUMN_CONTENT_KEYS.map((key) => [key, item[key] ?? ''])\r
17491
- ),\r
17492
- image: item.image,\r
17493
- link: item.link,\r
17494
- }));\r
17495
- }, [content, entriesCount]);\r
17496
- \r
17497
- const effectiveVisibleCount = cutEnabled\r
17498
- ? (visibleRowCount ?? cut)\r
17499
- : allRows.length;\r
17500
- \r
17501
- const visibleRows = useMemo(() => {\r
17502
- if (cutEnabled) {\r
17503
- return allRows.slice(0, effectiveVisibleCount);\r
17504
- }\r
17505
- return allRows;\r
17506
- }, [allRows, cutEnabled, effectiveVisibleCount]);\r
17507
- \r
17508
- const showCutLabel = cutEnabled && effectiveVisibleCount < allRows.length;\r
17509
- \r
17510
- const hasBetweenItemDividers = visibleRows.length > 1 || showCutLabel;\r
17511
- const dividerClassNames = [\r
17512
- showDividerTop ? \`\${P}-divider-top\` : '',\r
17513
- showDividerBottom || hasBetweenItemDividers ? \`\${P}-divider-bottom\` : '',\r
17514
- ].filter(Boolean).join(' ');\r
17515
- \r
17516
- const handleShowMore = () => {\r
17517
- const currentVisible = visibleRowCount ?? cut;\r
17518
- if (!showCut) {\r
17519
- setVisibleRowCount(allRows.length);\r
17520
- return;\r
17521
- }\r
17522
- setVisibleRowCount(Math.min(currentVisible + showCut, allRows.length));\r
17523
- };\r
17524
- \r
17525
- const scaled = (v: number) => scalingValue(v, isEditor ?? false);\r
17526
- const resolvedRowPaddingTop = isVerticalLayout\r
17527
- ? (rowPaddingTopB ?? 0)\r
17528
- : (rowPaddingTop ?? 0);\r
17529
- const resolvedRowPaddingBottom = rowPaddingBottom ?? 0;\r
17530
- const resolvedCellMinHeight = cellMinHeight ?? 0;\r
17531
- const rowPaddingTopControlKey = isVerticalLayout ? 'rowPaddingTopB' : 'rowPaddingTop';\r
17532
- const firstColumn = listColumns[0];\r
17533
- const lastColumn = listColumns[listColumns.length - 1];\r
17534
- const firstColumnEffectivePadding = effectiveColumnPaddings[0];\r
17535
- const lastColumnEffectivePadding = effectiveColumnPaddings[effectiveColumnPaddings.length - 1];\r
17536
- const firstColumnPaddingLeftWidth = firstColumn && firstColumnEffectivePadding\r
17537
- ? Math.max(firstColumnEffectivePadding.paddingLeft, COL_PADDING_HANDLE_WIDTH)\r
17538
- : 0;\r
17539
- const lastColumnPaddingRightWidth = lastColumn && lastColumnEffectivePadding\r
17540
- ? Math.max(lastColumnEffectivePadding.paddingRight, COL_PADDING_HANDLE_WIDTH)\r
17541
- : 0;\r
17542
- const columnsRightEdge = resolvedContentWidth;\r
17543
- \r
17544
- const getHoverImagePosition = (event: React.MouseEvent) => {\r
17545
- const container = containerRef.current;\r
17546
- if (!container) {\r
17547
- return { x: 0, y: 0 };\r
17548
- }\r
17549
- \r
17550
- const rect = container.getBoundingClientRect();\r
17551
- return {\r
17552
- x: event.clientX - rect.left + HOVER_IMAGE_CURSOR_OFFSET,\r
17553
- y: event.clientY - rect.top + HOVER_IMAGE_CURSOR_OFFSET,\r
17554
- };\r
17555
- };\r
17556
- \r
17557
- const handleRowMouseEnter = (row: ListItemRow, event: React.MouseEvent) => {\r
17558
- if (!showHoverImage) return;\r
17559
- \r
17560
- const image = row.image;\r
17561
- if (!image?.url) {\r
17562
- setHoverImage(null);\r
17563
- return;\r
17564
- }\r
17565
- \r
17566
- const { x, y } = getHoverImagePosition(event);\r
17567
- const minWidth = imageSize?.min ?? 80;\r
17568
- const maxWidth = imageSize?.max ?? 320;\r
17569
- const widthPx = hoverImage?.rowId === row.id\r
17570
- ? hoverImage.widthPx\r
17571
- : randomBetween(minWidth, maxWidth);\r
17572
- \r
17573
- setHoverImage({\r
17574
- rowId: row.id,\r
17575
- url: image.url,\r
17576
- objectFit: image.objectFit ?? 'cover',\r
17577
- widthPx,\r
17578
- x,\r
17579
- y,\r
17580
- });\r
17581
- };\r
17582
- \r
17583
- const handleWrapperMouseMove = (event: React.MouseEvent) => {\r
17584
- if (!showHoverImage || !hoverImage) return;\r
17585
- \r
17586
- const { x, y } = getHoverImagePosition(event);\r
17587
- setHoverImage((prev) => {\r
17588
- if (!prev) return prev;\r
17589
- if (prev.x === x && prev.y === y) return prev;\r
17590
- return { ...prev, x, y };\r
17591
- });\r
17592
- };\r
17593
- \r
17594
- const handleWrapperMouseLeave = () => {\r
17595
- setHoverImage(null);\r
17596
- };\r
17597
- \r
17598
- const hasBaselineColumn = useMemo(\r
17599
- () =>\r
17600
- !isVerticalLayout &&\r
17601
- COLUMN_TEXT_PREFIXES.some((prefix) => {\r
17602
- const columnLetter = prefix.charAt(0);\r
17603
- const valign = settings[\`\${prefix}VerticalAlign\` as ListColumnVerticalAlignKey];\r
17604
- return isActiveBaselineVAlign(valign, settings, columnLetter);\r
17605
- }),\r
17606
- [\r
17607
- isVerticalLayout,\r
17608
- settings,\r
17609
- settings.AColumnVerticalAlign,\r
17610
- settings.BColumnVerticalAlign,\r
17611
- settings.CColumnVerticalAlign,\r
17612
- settings.DColumnVerticalAlign,\r
17613
- settings.EColumnVerticalAlign,\r
17614
- ],\r
17615
- );\r
17616
- \r
17617
- useLayoutEffect(() => {\r
17618
- const container = containerRef.current;\r
17619
- if (!container) return;\r
17620
- \r
17621
- const clearBaselineStyles = () => {\r
17622
- container.querySelectorAll<HTMLElement>('[data-list-col]').forEach((el) => {\r
17623
- el.style.transform = '';\r
17624
- const listCol = el.querySelector<HTMLElement>(\`.\${P}-list-col\`);\r
17625
- if (listCol) {\r
17626
- listCol.style.minHeight = '';\r
17627
- listCol.style.height = '';\r
17628
- }\r
17629
- const title = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);\r
17630
- if (title) {\r
17631
- title.style.transform = '';\r
17632
- }\r
17633
- });\r
17634
- };\r
17635
- \r
17636
- if (isVerticalLayout || !hasBaselineColumn) {\r
17637
- clearBaselineStyles();\r
17638
- return;\r
17639
- }\r
17640
- \r
17641
- const applyBaselines = () => {\r
17642
- container.querySelectorAll<HTMLElement>('[data-list-row]').forEach((rowEl) => {\r
17643
- const cols = Array.from(rowEl.querySelectorAll<HTMLElement>('[data-list-col]'));\r
17644
- cols.forEach((el) => {\r
17645
- el.style.transform = '';\r
17646
- const listCol = el.querySelector<HTMLElement>(\`.\${P}-list-col\`);\r
17647
- if (listCol) {\r
17648
- listCol.style.minHeight = '';\r
17649
- listCol.style.height = '';\r
17650
- }\r
17651
- const title = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);\r
17652
- if (title) {\r
17653
- title.style.transform = '';\r
17654
- }\r
17655
- });\r
17656
- \r
17657
- syncRowListColHeights(rowEl, cols, \`\${P}-list-col\`);\r
17658
- void rowEl.offsetHeight;\r
17659
- const rowTop = rowEl.getBoundingClientRect().top;\r
17660
- \r
17661
- type ColInfo = {\r
17662
- el: HTMLElement;\r
17663
- titleEl: HTMLElement | null;\r
17664
- letter: string;\r
17665
- kind: string;\r
17666
- anchor: string | null;\r
17667
- };\r
17668
- \r
17669
- const probeClassName = \`\${P}-baseline-probe\`;\r
17670
- const byLetter = new Map<string, ColInfo>();\r
17671
- const infos: ColInfo[] = cols.map((el) => {\r
17672
- const titleEl = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);\r
17673
- const info: ColInfo = {\r
17674
- el,\r
17675
- titleEl,\r
17676
- letter: el.getAttribute('data-col-letter') ?? '',\r
17677
- kind: el.getAttribute('data-valign') ?? 'top',\r
17678
- anchor: el.getAttribute('data-valign-anchor'),\r
17679
- };\r
17680
- byLetter.set(info.letter, info);\r
17681
- return info;\r
17682
- });\r
17683
- \r
17684
- const finalBaseline = new Map<string, number>();\r
17685
- const resolve = (info: ColInfo, stack: Set<string>): number => {\r
17686
- const cached = finalBaseline.get(info.letter);\r
17687
- if (cached !== undefined) return cached;\r
17688
- \r
17689
- const anchor = info.anchor ? byLetter.get(info.anchor) : undefined;\r
17690
- if (info.kind !== 'baseline' || !anchor || stack.has(info.letter)) {\r
17691
- const baseline = measureColumnFirstLineBaselineOffset(\r
17692
- info,\r
17693
- rowTop,\r
17694
- \`\${P}-list-col\`,\r
17695
- probeClassName,\r
17696
- );\r
17697
- finalBaseline.set(info.letter, baseline);\r
17698
- return baseline;\r
17699
- }\r
17700
- \r
17701
- stack.add(info.letter);\r
17702
- const anchorBaseline = resolve(anchor, stack);\r
17703
- stack.delete(info.letter);\r
17704
- \r
17705
- const followerNatural = measureColumnFirstLineBaselineOffset(\r
17706
- info,\r
17707
- rowTop,\r
17708
- \`\${P}-list-col\`,\r
17709
- probeClassName,\r
17710
- );\r
17711
- const shift = anchorBaseline - followerNatural;\r
17712
- applyBaselineTitleShift(info.titleEl, shift);\r
17713
- \r
17714
- const result = measureColumnFirstLineBaselineOffset(\r
17715
- info,\r
17716
- rowTop,\r
17717
- \`\${P}-list-col\`,\r
17718
- probeClassName,\r
17719
- );\r
17720
- finalBaseline.set(info.letter, result);\r
17721
- return result;\r
17722
- };\r
17723
- \r
17724
- infos.forEach((info) => resolve(info, new Set<string>()));\r
17725
- });\r
17726
- };\r
17727
- \r
17728
- applyBaselines();\r
17729
- \r
17730
- const observer = new ResizeObserver(() => applyBaselines());\r
17731
- observer.observe(container);\r
17732
- \r
17733
- let cancelled = false;\r
17734
- if (typeof document !== 'undefined' && document.fonts?.ready) {\r
17735
- document.fonts.ready.then(() => {\r
17736
- if (!cancelled) applyBaselines();\r
17737
- });\r
17738
- }\r
17739
- \r
17740
- return () => {\r
17741
- cancelled = true;\r
17742
- observer.disconnect();\r
17743
- clearBaselineStyles();\r
17744
- };\r
17745
- }, [\r
17746
- hasBaselineColumn,\r
17747
- isVerticalLayout,\r
17748
- settings,\r
17749
- content,\r
17750
- designWidth,\r
17751
- visibleRows,\r
17752
- effectiveColumnWidths,\r
17753
- ]);\r
17754
- \r
17755
- return (\r
17756
- <>\r
17757
- <style dangerouslySetInnerHTML={{ __html: getCSS(P) }} />\r
17758
- <div style={colorVars}>\r
17759
- <div\r
17760
- ref={containerRef}\r
17761
- className={\`\${P}-wrapper \${wrapperStateClasses}\${dividerClassNames ? \` \${dividerClassNames}\` : ''}\${isVerticalLayout ? \` \${P}-type-b\` : ''}\`.trim()}\r
17762
- style={{\r
17763
- width: scalingValue(wrapperWidth ?? 0, isEditor),\r
17764
- }}\r
17765
- onMouseMove={showHoverImage ? handleWrapperMouseMove : undefined}\r
17766
- onMouseLeave={showHoverImage ? handleWrapperMouseLeave : undefined}\r
17767
- >\r
17768
- <div style={{ width: '100%' }}>\r
17769
- {visibleRows.map((row, rowIdx) => {\r
17770
- const hasLink = (row.link?.length ?? 0) > 0;\r
17771
- const RowElement = hasLink ? 'a' : 'div';\r
17772
- const rowStyle = getEntryDividerWidths(\r
17773
- rowIdx,\r
17774
- visibleRows.length,\r
17775
- showDividerTop,\r
17776
- showDividerBottom,\r
17777
- showCutLabel,\r
17778
- dividerWidth ?? 0,\r
17779
- isEditor ?? false,\r
17780
- );\r
17781
- \r
17782
- return (\r
17783
- <RowElement\r
17784
- key={row.id}\r
17785
- className={\`\${P}-list-item\${hasLink ? \` \${P}-list-item-has-link\` : ''}\`}\r
17786
- {...(hasLink ? { href: row.link, target: '_blank' } : {})}\r
17787
- style={rowStyle}\r
17788
- onMouseEnter={showHoverImage ? (event) => handleRowMouseEnter(row, event) : undefined}\r
17789
- >\r
17790
- {(resolvedRowPaddingTop > 0 || showControls) && (\r
17791
- <div\r
17792
- {...(showControls ? {\r
17793
- 'data-controls': rowPaddingTopControlKey,\r
17794
- 'data-controls-axis': 'y',\r
17795
- 'data-controls-min': '0',\r
17796
- } : {})}\r
17797
- className={\`\${P}-row-padding-handle\`}\r
17798
- style={{ height: scaled(resolvedRowPaddingTop) }}\r
17799
- />\r
17800
- )}\r
17801
- <div\r
17802
- className={\`\${P}-list-cols-row\${isVerticalLayout ? '' : \` \${P}-list-cols-row-h\`}\`}\r
17803
- {...(isVerticalLayout ? {} : { 'data-list-row': '' })}\r
17804
- style={isVerticalLayout ? undefined : { minHeight: scaled(resolvedCellMinHeight) }}\r
17805
- >\r
17806
- {listColumns.map((col, colIndex) => {\r
17807
- const isLastColumn = colIndex === listColumns.length - 1;\r
17808
- const effectivePadding = effectiveColumnPaddings[colIndex];\r
17809
- const columnPaddingBottom = col.paddingBottom;\r
17810
- const hasColumnText = hasListColumnText(row.cells[col.key]);\r
17811
- const showColumnPaddingBottom = isVerticalLayout\r
17812
- && hasColumnText\r
17813
- && (columnPaddingBottom > 0 || showControls);\r
17814
- const columnSizeStyle = isVerticalLayout\r
17815
- ? { minHeight: scaled(resolvedCellMinHeight) }\r
17816
- : (isLastColumn ? {} : { width: scaled(effectiveColumnWidths[colIndex]) });\r
17817
- const columnPaddingStyle = isVerticalLayout\r
17818
- ? {\r
17819
- paddingLeft: scaled(effectiveTextPaddingLR),\r
17820
- paddingRight: scaled(effectiveTextPaddingLR),\r
17821
- }\r
17822
- : {\r
17823
- paddingLeft: scaled(effectivePadding.paddingLeft),\r
17824
- paddingRight: scaled(effectivePadding.paddingRight),\r
17825
- };\r
17826
- const columnLetter = col.textPrefix.charAt(0);\r
17827
- const vAlign = isVerticalLayout\r
17828
- ? { kind: 'top' as const }\r
17829
- : resolveColumnVerticalAlign(\r
17830
- settings[\`\${col.textPrefix}VerticalAlign\` as ListColumnVerticalAlignKey],\r
17831
- settings,\r
17832
- columnLetter,\r
17833
- );\r
17834
- \r
17835
- return (\r
17836
- <div\r
17837
- key={col.key}\r
17838
- {...(isVerticalLayout\r
17839
- ? {}\r
17840
- : {\r
17841
- 'data-list-col': '',\r
17842
- 'data-col-letter': columnLetter,\r
17843
- 'data-valign': vAlign.kind,\r
17844
- ...(vAlign.kind === 'baseline'\r
17845
- ? { 'data-valign-anchor': vAlign.anchorLetter }\r
17846
- : {}),\r
17847
- })}\r
17848
- >\r
17849
- <div\r
17850
- className={\`\${P}-list-col\${isLastColumn ? \` \${P}-list-col-last\` : ''}\`}\r
17851
- style={{\r
17852
- ...columnPaddingStyle,\r
17853
- ...columnSizeStyle,\r
17854
- }}\r
17855
- data-test={col.width}\r
17856
- >\r
17857
- <span\r
17858
- className={getListColumnTitleClassName(\r
17859
- settings,\r
17860
- col.textPrefix,\r
17861
- \`\${P}-list-col-title\`,\r
17862
- \`\${P}-text-tight-leading\`,\r
17863
- )}\r
17864
- style={{\r
17865
- ...listColumnTextFieldsToCss(resolveListColumnTextFields(settings, col.textPrefix), isEditor),\r
17866
- ...getListColumnTitleVars(settings, col.textPrefix, P, isEditor),\r
17867
- ...(!isVerticalLayout ? vAlignToTitleStyle(vAlign.kind) : {}),\r
17868
- }}\r
17869
- >\r
17870
- {row.cells[col.key] ?? null}\r
17871
- </span>\r
17872
- </div>\r
17873
- {showColumnPaddingBottom && (\r
17874
- <div\r
17875
- {...(showControls ? {\r
17876
- 'data-controls': col.paddingBottomKey,\r
17877
- 'data-controls-axis': 'y',\r
17878
- 'data-controls-min': '0',\r
17879
- } : {})}\r
17880
- className={\`\${P}-row-padding-handle\`}\r
17881
- style={{ height: scaled(columnPaddingBottom) }}\r
17882
- />\r
17883
- )}\r
17884
- </div>\r
17885
- );\r
17886
- })}\r
17887
- </div>\r
17888
- {!isVerticalLayout && (resolvedRowPaddingBottom > 0 || showControls) && (\r
17889
- <div\r
17890
- {...(showControls ? {\r
17891
- 'data-controls': 'rowPaddingBottom',\r
17892
- 'data-controls-axis': 'y',\r
17893
- 'data-controls-min': '0',\r
17894
- } : {})}\r
17895
- className={\`\${P}-row-padding-handle\`}\r
17896
- style={{ height: scaled(resolvedRowPaddingBottom) }}\r
17897
- />\r
17898
- )}\r
17899
- </RowElement>\r
17900
- );\r
17901
- })}\r
17902
- {showCutLabel && (\r
17903
- <button\r
17904
- type="button"\r
17905
- className={\`\${P}-cut-item\`}\r
17906
- style={{\r
17907
- minHeight: scaled(cutCellMinHeight ?? 0),\r
17908
- ...getCutItemDividerWidths(\r
17909
- showDividerBottom,\r
17910
- dividerWidth ?? 0,\r
17911
- isEditor ?? false,\r
17912
- ),\r
17913
- }}\r
17914
- onClick={handleShowMore}\r
17915
- >\r
17916
- <div\r
17917
- className={\`\${P}-list-cols-row\`}\r
17918
- style={\r
17919
- isVerticalLayout\r
17920
- ? {\r
17921
- paddingLeft: scaled(effectiveTextPaddingLR),\r
17922
- paddingRight: scaled(effectiveTextPaddingLR),\r
17923
- }\r
17924
- : { justifyContent: 'center' }\r
17925
- }\r
17926
- >\r
17927
- <span\r
17928
- className={getListColumnTitleClassName(\r
17929
- settings,\r
17930
- CUT_LABEL_TEXT_PREFIX,\r
17931
- \`\${P}-cut-label\`,\r
17932
- \`\${P}-text-tight-leading\`,\r
17933
- )}\r
17934
- style={{\r
17935
- ...listColumnTextFieldsToCss(resolveListColumnTextFields(settings, CUT_LABEL_TEXT_PREFIX), isEditor),\r
17936
- ...getListColumnTitleVars(settings, CUT_LABEL_TEXT_PREFIX, P, isEditor),\r
17937
- }}\r
17938
- >\r
17939
- {cutLabel}\r
17940
- </span>\r
17941
- </div>\r
17942
- </button>\r
17943
- )}\r
17944
- </div>\r
17945
- {showControls && !isVerticalLayout && firstColumn && lastColumn && (\r
17946
- <div key="column-edge-padding-handles" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\r
17947
- <div\r
17948
- data-controls={firstColumn.paddingLeftKey}\r
17949
- data-controls-axis="x"\r
17950
- data-controls-variant="column-padding"\r
17951
- data-controls-min="0"\r
17952
- data-controls-max-fraction={String(\r
17953
- effectiveColumnWidths[0] - (firstColumnEffectivePadding?.paddingRight ?? 0),\r
17954
- )}\r
17955
- data-controls-static-handle=""\r
17956
- className={\`\${P}-padding-control-handle\`}\r
17957
- style={{\r
17958
- position: 'absolute',\r
17959
- top: 0,\r
17960
- left: 0,\r
17961
- width: scaled(firstColumnPaddingLeftWidth),\r
17962
- height: '100%',\r
17963
- pointerEvents: 'auto',\r
17964
- zIndex: 2,\r
17965
- }}\r
17966
- />\r
17967
- <div\r
17968
- data-controls={lastColumn.paddingRightKey}\r
17969
- data-controls-axis="x"\r
17970
- data-controls-variant="column-padding"\r
17971
- data-controls-reverse=""\r
17972
- data-controls-min="0"\r
17973
- data-controls-max-fraction={String(\r
17974
- effectiveColumnWidths[listColumns.length - 1]\r
17975
- - (lastColumnEffectivePadding?.paddingLeft ?? 0),\r
17976
- )}\r
17977
- data-controls-static-handle=""\r
17978
- className={\`\${P}-padding-control-handle\`}\r
17979
- style={{\r
17980
- position: 'absolute',\r
17981
- top: 0,\r
17982
- left: scaled(columnsRightEdge - lastColumnPaddingRightWidth),\r
17983
- width: scaled(lastColumnPaddingRightWidth),\r
17984
- height: '100%',\r
17985
- pointerEvents: 'auto',\r
17986
- zIndex: 2,\r
17987
- }}\r
17988
- />\r
17989
- </div>\r
17990
- )}\r
17991
- {showControls && !isVerticalLayout && listColumns.slice(0, -1).map((col, colIndex) => {\r
17992
- const nextCol = listColumns[colIndex + 1];\r
17993
- const maxColumnWidth = getColumnMaxWidth(\r
17994
- colIndex,\r
17995
- resolvedColumnWidths,\r
17996
- storedColumnWidths,\r
17997
- resolvedContentWidth,\r
17998
- );\r
17999
- const boundaryOffset = resolvedColumnWidths.slice(0, colIndex + 1).reduce((sum, width) => sum + width, 0);\r
18000
- const colEffectivePadding = effectiveColumnPaddings[colIndex];\r
18001
- const nextColEffectivePadding = effectiveColumnPaddings[colIndex + 1];\r
18002
- const paddingRightWidth = Math.max(\r
18003
- colEffectivePadding.paddingRight,\r
18004
- COL_PADDING_HANDLE_WIDTH,\r
18005
- );\r
18006
- const paddingLeftWidth = Math.max(\r
18007
- nextColEffectivePadding.paddingLeft,\r
18008
- COL_PADDING_HANDLE_WIDTH,\r
18009
- );\r
18010
- const columnWidthHandleOffset = boundaryOffset - COL_RESIZE_HANDLE_WIDTH / 2;\r
18011
- \r
18012
- return (\r
18013
- <div key={\`\${col.widthKey}-junction\`} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\r
18014
- <div\r
18015
- data-controls={col.paddingRightKey}\r
18016
- data-controls-axis="x"\r
18017
- data-controls-variant="column-padding"\r
18018
- data-controls-reverse=""\r
18019
- data-controls-min="0"\r
18020
- data-controls-max-fraction={String(\r
18021
- effectiveColumnWidths[colIndex] - colEffectivePadding.paddingLeft,\r
18022
- )}\r
18023
- data-controls-static-handle=""\r
18024
- className={\`\${P}-padding-control-handle\`}\r
18025
- style={{\r
18026
- position: 'absolute',\r
18027
- top: 0,\r
18028
- left: scaled(boundaryOffset - paddingRightWidth),\r
18029
- width: scaled(paddingRightWidth),\r
18030
- height: '100%',\r
18031
- pointerEvents: 'auto',\r
18032
- zIndex: 2,\r
18033
- }}\r
18034
- />\r
18035
- <div\r
18036
- data-controls={col.widthKey}\r
18037
- data-controls-axis="x"\r
18038
- data-controls-min={String(MIN_COLUMN_WIDTH_PX)}\r
18039
- data-controls-max-fraction={String(maxColumnWidth)}\r
18040
- data-controls-variant="column-width"\r
18041
- className={\`\${P}-col-resize-handle\`}\r
18042
- style={{\r
18043
- position: 'absolute',\r
18044
- top: '0px',\r
18045
- left: scaled(columnWidthHandleOffset),\r
18046
- width: scaled(COL_RESIZE_HANDLE_WIDTH),\r
18047
- height: 'calc(100%)',\r
18048
- pointerEvents: 'auto',\r
18049
- zIndex: 4,\r
18050
- }}\r
18051
- />\r
18052
- <div\r
18053
- data-controls={nextCol.paddingLeftKey}\r
18054
- data-controls-axis="x"\r
18055
- data-controls-variant="column-padding"\r
18056
- data-controls-min="0"\r
18057
- data-controls-max-fraction={String(\r
18058
- effectiveColumnWidths[colIndex + 1] - nextColEffectivePadding.paddingRight,\r
18059
- )}\r
18060
- data-controls-static-handle=""\r
18061
- className={\`\${P}-padding-control-handle\`}\r
18062
- style={{\r
18063
- position: 'absolute',\r
18064
- top: 0,\r
18065
- left: scaled(boundaryOffset),\r
18066
- width: scaled(paddingLeftWidth),\r
18067
- height: '100%',\r
18068
- pointerEvents: 'auto',\r
18069
- zIndex: 2,\r
18070
- }}\r
18071
- />\r
18072
- </div>\r
18073
- );\r
18074
- })}\r
18075
- {showControls && isVerticalLayout && (\r
18076
- <div key="text-padding-lr-handles" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\r
18077
- <div\r
18078
- data-controls="textPaddingLR"\r
18079
- data-controls-paired=""\r
18080
- data-controls-axis="x"\r
18081
- data-controls-min="0"\r
18082
- data-controls-max-fraction={String(textPaddingLRMaxFraction)}\r
18083
- data-controls-static-handle=""\r
18084
- className={\`\${P}-text-padding-lr-handle\`}\r
18085
- style={{\r
18086
- position: 'absolute',\r
18087
- top: 0,\r
18088
- left: 0,\r
18089
- width: scaled(textPaddingLRHandleWidth),\r
18090
- height: '100%',\r
18091
- pointerEvents: 'auto',\r
18092
- zIndex: 2,\r
18093
- }}\r
18094
- />\r
18095
- <div\r
18096
- data-controls="textPaddingLR"\r
18097
- data-controls-paired=""\r
18098
- data-controls-axis="x"\r
18099
- data-controls-reverse=""\r
18100
- data-controls-min="0"\r
18101
- data-controls-max-fraction={String(textPaddingLRMaxFraction)}\r
18102
- data-controls-static-handle=""\r
18103
- className={\`\${P}-text-padding-lr-handle\`}\r
18104
- style={{\r
18105
- position: 'absolute',\r
18106
- top: 0,\r
18107
- left: scaled(Math.max(textPaddingLRHandleWidth, resolvedContentWidth - textPaddingLRHandleWidth)),\r
18108
- width: scaled(textPaddingLRHandleWidth),\r
18109
- height: '100%',\r
18110
- pointerEvents: 'auto',\r
18111
- zIndex: 2,\r
18112
- }}\r
18113
- />\r
18114
- </div>\r
18115
- )}\r
18116
- {showHoverImage && hoverImage && (\r
18117
- <img\r
18118
- className={\`\${P}-hover-image\`}\r
18119
- src={hoverImage.url}\r
18120
- alt=""\r
18121
- style={{\r
18122
- width: sv(hoverImage.widthPx),\r
18123
- objectFit: hoverImage.objectFit,\r
18124
- left: hoverImage.x,\r
18125
- top: hoverImage.y,\r
18126
- }}\r
18127
- />\r
18128
- )}\r
18129
- </div>\r
18130
- </div>\r
18131
- </>\r
18132
- );\r
18133
- }\r
15593
+ const kd = `import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
15594
+ import { CommonComponentProps } from '../props';
15595
+ import { buildColorVars, scalingValue, useScopedStyles } from '../utils/index';
15596
+ import { omitTextColors, TextStyles, textStylesToCss } from '../utils/textStylesToCss';
15597
+
15598
+ type ListFontSettings = { fontWeight: number; fontStyle: string };
15599
+
15600
+ type ListColumnPrefix = 'AColumn' | 'BColumn' | 'CColumn' | 'DColumn' | 'EColumn';
15601
+
15602
+ type ListColumnTextStyleOverrides = {
15603
+ AColumnVerticalAlign?: string;
15604
+ AColumnTextFontFamily?: string;
15605
+ AColumnTextFontSettings?: ListFontSettings;
15606
+ AColumnTextFontSize?: number;
15607
+ AColumnTextLineHeight?: number;
15608
+ AColumnTextLetterSpacing?: number;
15609
+ AColumnTextWordSpacing?: number;
15610
+ AColumnTextTextAppearance?: TextStyles['textAppearance'];
15611
+ BColumnVerticalAlign?: string;
15612
+ BColumnTextFontFamily?: string;
15613
+ BColumnTextFontSettings?: ListFontSettings;
15614
+ BColumnTextFontSize?: number;
15615
+ BColumnTextLineHeight?: number;
15616
+ BColumnTextLetterSpacing?: number;
15617
+ BColumnTextWordSpacing?: number;
15618
+ BColumnTextTextAppearance?: TextStyles['textAppearance'];
15619
+ CColumnVerticalAlign?: string;
15620
+ CColumnTextFontFamily?: string;
15621
+ CColumnTextFontSettings?: ListFontSettings;
15622
+ CColumnTextFontSize?: number;
15623
+ CColumnTextLineHeight?: number;
15624
+ CColumnTextLetterSpacing?: number;
15625
+ CColumnTextWordSpacing?: number;
15626
+ CColumnTextTextAppearance?: TextStyles['textAppearance'];
15627
+ DColumnVerticalAlign?: string;
15628
+ DColumnTextFontFamily?: string;
15629
+ DColumnTextFontSettings?: ListFontSettings;
15630
+ DColumnTextFontSize?: number;
15631
+ DColumnTextLineHeight?: number;
15632
+ DColumnTextLetterSpacing?: number;
15633
+ DColumnTextWordSpacing?: number;
15634
+ DColumnTextTextAppearance?: TextStyles['textAppearance'];
15635
+ EColumnVerticalAlign?: string;
15636
+ EColumnTextFontFamily?: string;
15637
+ EColumnTextFontSettings?: ListFontSettings;
15638
+ EColumnTextFontSize?: number;
15639
+ EColumnTextLineHeight?: number;
15640
+ EColumnTextLetterSpacing?: number;
15641
+ EColumnTextWordSpacing?: number;
15642
+ EColumnTextTextAppearance?: TextStyles['textAppearance'];
15643
+ cutLabelTextFontFamily?: string;
15644
+ cutLabelTextFontSettings?: ListFontSettings;
15645
+ cutLabelTextFontSize?: number;
15646
+ cutLabelTextLineHeight?: number;
15647
+ cutLabelTextLetterSpacing?: number;
15648
+ cutLabelTextWordSpacing?: number;
15649
+ cutLabelTextTextAppearance?: TextStyles['textAppearance'];
15650
+ };
15651
+
15652
+ export type ListColumnVerticalAlignKey = \`\${ListColumnPrefix}VerticalAlign\`;
15653
+
15654
+ type ListColumnVerticalAlignUpdates = {
15655
+ AColumnVerticalAlign?: string;
15656
+ BColumnVerticalAlign?: string;
15657
+ CColumnVerticalAlign?: string;
15658
+ DColumnVerticalAlign?: string;
15659
+ EColumnVerticalAlign?: string;
15660
+ };
15661
+
15662
+ type ListColumnTextStyleSyncUpdates = {
15663
+ AColumnTextFontFamily?: string;
15664
+ AColumnTextFontSettings?: ListFontSettings;
15665
+ AColumnTextFontSize?: number;
15666
+ AColumnTextLineHeight?: number;
15667
+ AColumnTextLetterSpacing?: number;
15668
+ AColumnTextWordSpacing?: number;
15669
+ AColumnTextTextAppearance?: TextStyles['textAppearance'];
15670
+ BColumnTextFontFamily?: string;
15671
+ BColumnTextFontSettings?: ListFontSettings;
15672
+ BColumnTextFontSize?: number;
15673
+ BColumnTextLineHeight?: number;
15674
+ BColumnTextLetterSpacing?: number;
15675
+ BColumnTextWordSpacing?: number;
15676
+ BColumnTextTextAppearance?: TextStyles['textAppearance'];
15677
+ CColumnTextFontFamily?: string;
15678
+ CColumnTextFontSettings?: ListFontSettings;
15679
+ CColumnTextFontSize?: number;
15680
+ CColumnTextLineHeight?: number;
15681
+ CColumnTextLetterSpacing?: number;
15682
+ CColumnTextWordSpacing?: number;
15683
+ CColumnTextTextAppearance?: TextStyles['textAppearance'];
15684
+ DColumnTextFontFamily?: string;
15685
+ DColumnTextFontSettings?: ListFontSettings;
15686
+ DColumnTextFontSize?: number;
15687
+ DColumnTextLineHeight?: number;
15688
+ DColumnTextLetterSpacing?: number;
15689
+ DColumnTextWordSpacing?: number;
15690
+ DColumnTextTextAppearance?: TextStyles['textAppearance'];
15691
+ EColumnTextFontFamily?: string;
15692
+ EColumnTextFontSettings?: ListFontSettings;
15693
+ EColumnTextFontSize?: number;
15694
+ EColumnTextLineHeight?: number;
15695
+ EColumnTextLetterSpacing?: number;
15696
+ EColumnTextWordSpacing?: number;
15697
+ EColumnTextTextAppearance?: TextStyles['textAppearance'];
15698
+ cutLabelTextFontFamily?: string;
15699
+ cutLabelTextFontSettings?: ListFontSettings;
15700
+ cutLabelTextFontSize?: number;
15701
+ cutLabelTextLineHeight?: number;
15702
+ cutLabelTextLetterSpacing?: number;
15703
+ cutLabelTextWordSpacing?: number;
15704
+ cutLabelTextTextAppearance?: TextStyles['textAppearance'];
15705
+ };
15706
+
15707
+ export type ListSettings = {
15708
+ columns: number;
15709
+ type: 'A' | 'B';
15710
+ wrapperWidth: number;
15711
+ entriesCount: number;
15712
+ cellMinHeight: number;
15713
+ imageOnHover: 'On' | 'Off';
15714
+ imageSize?: { min: number; max: number };
15715
+ dividerWidth: number;
15716
+ showVisibility: boolean[];
15717
+ cut: number;
15718
+ showCut: number;
15719
+ cutCellMinHeight: number;
15720
+ cutLabel: string;
15721
+ entryHoverEffect: 'None' | 'Default' | 'Blinds';
15722
+ rowPaddingTop: number;
15723
+ rowPaddingBottom: number;
15724
+ rowPaddingTopB: number;
15725
+ AColumnWidth: number;
15726
+ AColumnPaddingLeft: number;
15727
+ AColumnPaddingRight: number;
15728
+ AColumnPaddingBottom: number;
15729
+ BColumnWidth: number;
15730
+ BColumnPaddingLeft: number;
15731
+ BColumnPaddingRight: number;
15732
+ BColumnPaddingBottom: number;
15733
+ CColumnWidth: number;
15734
+ CColumnPaddingLeft: number;
15735
+ CColumnPaddingRight: number;
15736
+ CColumnPaddingBottom: number;
15737
+ DColumnWidth: number;
15738
+ DColumnPaddingLeft: number;
15739
+ DColumnPaddingRight: number;
15740
+ DColumnPaddingBottom: number;
15741
+ EColumnWidth: number;
15742
+ EColumnPaddingLeft: number;
15743
+ EColumnPaddingRight: number;
15744
+ EColumnPaddingBottom: number;
15745
+ columnsOrder?: string[];
15746
+ textPaddingLR?: number;
15747
+ textColor: string;
15748
+ textFontFamily: string;
15749
+ textFontSettings?: ListFontSettings;
15750
+ textFontSize?: number;
15751
+ textLineHeight?: number;
15752
+ textLetterSpacing?: number;
15753
+ textWordSpacing?: number;
15754
+ textTextAppearance?: TextStyles['textAppearance'];
15755
+ backgroundColor: string;
15756
+ dividerColor: string;
15757
+ textHoverColor: string;
15758
+ backgroundHoverColor: string;
15759
+ dividerHoverColor: string;
15760
+ } & ListColumnTextStyleOverrides;
15761
+
15762
+ type ListContentItem = {
15763
+ AColumn?: string;
15764
+ BColumnWidth?: string;
15765
+ CColumnWidth?: string;
15766
+ DColumnWidth?: string;
15767
+ EColumnWidth?: string;
15768
+ image?: {
15769
+ objectFit?: 'cover' | 'contain';
15770
+ url: string;
15771
+ name: string;
15772
+ };
15773
+ link?: string;
15774
+ };
15775
+
15776
+ type ListItemRow = {
15777
+ id: string | number;
15778
+ cells: Record<string, React.ReactNode>;
15779
+ image?: ListContentItem['image'];
15780
+ link?: string;
15781
+ };
15782
+
15783
+ type HoverImageState = {
15784
+ rowId: string | number;
15785
+ url: string;
15786
+ objectFit: 'cover' | 'contain';
15787
+ widthPx: number;
15788
+ x: number;
15789
+ y: number;
15790
+ };
15791
+
15792
+ type ListProps = {
15793
+ layoutId?: string;
15794
+ settings: ListSettings;
15795
+ content?: ListContentItem[];
15796
+ isEditor?: boolean;
15797
+ isPreviewMode?: boolean;
15798
+ activeEvent: string | undefined;
15799
+ onUpdateSettings?: (settings: ListSettings) => void;
15800
+ } & CommonComponentProps;
15801
+
15802
+ function sv(px: number): string {
15803
+ return \`calc(var(--cntrl-article-width, 100vw) * \${px / 1440})\`;
15804
+ }
15805
+
15806
+ function hasListColumnText(value: React.ReactNode): boolean {
15807
+ return String(value ?? '').trim().length > 0;
15808
+ }
15809
+
15810
+ function getEntryDividerWidths(
15811
+ rowIdx: number,
15812
+ rowCount: number,
15813
+ showDividerTop: boolean,
15814
+ showDividerBottom: boolean,
15815
+ hasCutItem: boolean,
15816
+ dividerWidth: number,
15817
+ isEditor: boolean,
15818
+ ): { borderTopWidth: string; borderBottomWidth: string } {
15819
+ const scaledDividerWidth = scalingValue(dividerWidth, isEditor);
15820
+ const none = scalingValue(0, isEditor);
15821
+
15822
+ const isFirst = rowIdx === 0;
15823
+ const isLastEntry = rowIdx === rowCount - 1 && !hasCutItem;
15824
+
15825
+ const borderTopWidth = isFirst && showDividerTop ? scaledDividerWidth : none;
15826
+ const borderBottomWidth = !isLastEntry || showDividerBottom ? scaledDividerWidth : none;
15827
+
15828
+ return { borderTopWidth, borderBottomWidth };
15829
+ }
15830
+
15831
+ function getCutItemDividerWidths(
15832
+ showDividerBottom: boolean,
15833
+ dividerWidth: number,
15834
+ isEditor: boolean,
15835
+ ): { borderTopWidth: string; borderBottomWidth: string } {
15836
+ const scaledDividerWidth = scalingValue(dividerWidth, isEditor);
15837
+ const none = scalingValue(0, isEditor);
15838
+
15839
+ return {
15840
+ borderTopWidth: none,
15841
+ borderBottomWidth: showDividerBottom ? scaledDividerWidth : none,
15842
+ };
15843
+ }
15844
+
15845
+ const HOVER_IMAGE_CURSOR_OFFSET = 10;
15846
+
15847
+ function getCSS(P: string): string {
15848
+ return \`
15849
+ .\${P}-wrapper {
15850
+ display: grid;
15851
+ align-items: start;
15852
+ min-height: \${sv(48)};
15853
+ position: relative;
15854
+ overflow: visible;
15855
+ box-sizing: border-box;
15856
+ }
15857
+
15858
+ .\${P}-hover-image {
15859
+ position: absolute;
15860
+ left: 0;
15861
+ top: 0;
15862
+ z-index: 10;
15863
+ pointer-events: none;
15864
+ display: block;
15865
+ height: auto;
15866
+ }
15867
+
15868
+ .\${P}-list-item {
15869
+ display: flex;
15870
+ flex-direction: column;
15871
+ align-items: stretch;
15872
+ width: 100%;
15873
+ overflow: visible;
15874
+ position: relative;
15875
+ box-sizing: content-box;
15876
+ user-select: none;
15877
+ background: var(--\${P}-background-color);
15878
+ }
15879
+
15880
+ .\${P}-wrapper.\${P}-divider-top .\${P}-list-item {
15881
+ border-top-style: solid;
15882
+ border-top-color: var(--\${P}-divider-color);
15883
+ }
15884
+
15885
+ .\${P}-wrapper.\${P}-divider-bottom .\${P}-list-item {
15886
+ border-bottom-style: solid;
15887
+ border-bottom-color: var(--\${P}-divider-color);
15888
+ }
15889
+
15890
+ .\${P}-list-cols-row {
15891
+ display: flex;
15892
+ align-items: start;
15893
+ width: 100%;
15894
+ box-sizing: border-box;
15895
+ }
15896
+
15897
+ .\${P}-list-cols-row-h {
15898
+ align-items: stretch;
15899
+ }
15900
+
15901
+ .\${P}-list-cols-row-h [data-list-col] {
15902
+ display: grid;
15903
+ grid-template-rows: minmax(0, 1fr);
15904
+ align-self: stretch;
15905
+ min-height: min-content;
15906
+ }
15907
+
15908
+ .\${P}-list-cols-row-h .\${P}-list-col {
15909
+ display: flex;
15910
+ flex-direction: column;
15911
+ align-items: flex-start;
15912
+ justify-content: flex-start;
15913
+ width: 100%;
15914
+ min-height: 0;
15915
+ }
15916
+
15917
+ .\${P}-list-cols-row-h .\${P}-list-col-title {
15918
+ display: block;
15919
+ flex: 0 0 auto;
15920
+ align-self: stretch;
15921
+ }
15922
+
15923
+ .\${P}-text-tight-leading {
15924
+ display: block;
15925
+ flex-shrink: 0;
15926
+ padding-top: var(--\${P}-title-leading-gap, 0);
15927
+ padding-bottom: var(--\${P}-title-leading-gap, 0);
15928
+ }
15929
+
15930
+ .\${P}-wrapper.\${P}-type-b .\${P}-list-cols-row {
15931
+ flex-direction: column;
15932
+ align-items: stretch;
15933
+ }
15934
+
15935
+ .\${P}-wrapper.\${P}-type-b .\${P}-list-col {
15936
+ width: 100%;
15937
+ min-width: 0;
15938
+ flex-direction: column;
15939
+ justify-content: flex-start;
15940
+ align-items: flex-start;
15941
+ min-height: min-content;
15942
+ }
15943
+
15944
+ .\${P}-wrapper.\${P}-type-b .\${P}-list-col-title {
15945
+ display: block;
15946
+ flex: 0 0 auto;
15947
+ align-self: stretch;
15948
+ text-align: center;
15949
+ }
15950
+
15951
+ .\${P}-wrapper.\${P}-type-b .\${P}-cut-item .\${P}-list-cols-row {
15952
+ flex-direction: row;
15953
+ align-items: center;
15954
+ justify-content: center;
15955
+ }
15956
+
15957
+ .\${P}-wrapper.\${P}-type-b .\${P}-cut-label {
15958
+ text-align: center;
15959
+ width: 100%;
15960
+ box-sizing: border-box;
15961
+ }
15962
+
15963
+ .\${P}-wrapper.\${P}-type-b .\${P}-list-col-last {
15964
+ flex: 0 0 auto;
15965
+ min-width: 0;
15966
+ }
15967
+
15968
+ a.\${P}-list-item {
15969
+ text-decoration: none;
15970
+ color: inherit;
15971
+ cursor: pointer;
15972
+ }
15973
+
15974
+ .\${P}-list-col {
15975
+ flex-shrink: 0;
15976
+ overflow: visible;
15977
+ box-sizing: border-box;
15978
+ min-width: \${sv(50)};
15979
+ position: relative;
15980
+ display: flex;
15981
+ align-items: flex-start;
15982
+ }
15983
+
15984
+ .\${P}-list-col-last {
15985
+ flex: 1 1 auto;
15986
+ min-width: \${sv(50)};
15987
+ }
15988
+
15989
+ .\${P}-list-col-title {
15990
+ color: var(--\${P}-text-color);
15991
+ white-space: pre-wrap;
15992
+ overflow-wrap: anywhere;
15993
+ word-break: break-word;
15994
+ flex: 1;
15995
+ min-width: 0;
15996
+ width: 100%;
15997
+ box-sizing: border-box;
15998
+ }
15999
+
16000
+ .\${P}-baseline-probe {
16001
+ display: inline-block;
16002
+ width: 0;
16003
+ height: 0;
16004
+ overflow: hidden;
16005
+ vertical-align: baseline;
16006
+ }
16007
+
16008
+ .\${P}-col-resize-handle,
16009
+ .\${P}-padding-control-handle {
16010
+ background: transparent;
16011
+ }
16012
+
16013
+ .\${P}-row-padding-handle {
16014
+ position: relative;
16015
+ z-index: 2;
16016
+ width: 100%;
16017
+ flex-shrink: 0;
16018
+ background: transparent;
16019
+ }
16020
+
16021
+ .\${P}-row-padding-handle::before {
16022
+ content: "";
16023
+ position: absolute;
16024
+ top: 0;
16025
+ left: 0;
16026
+ width: 100%;
16027
+ height: 100%;
16028
+ min-height: 20px;
16029
+ pointer-events: auto;
16030
+ z-index: 10;
16031
+ }
16032
+
16033
+ .\${P}-col-resize-handle::after {
16034
+ content: '';
16035
+ position: absolute;
16036
+ top: 0;
16037
+ left: 50%;
16038
+ transform: translateX(-50%);
16039
+ width: 2px;
16040
+ height: 100%;
16041
+ background: #FF5C02;
16042
+ pointer-events: none;
16043
+ }
16044
+
16045
+ .\${P}-wrapper.\${P}-type-b .\${P}-col-resize-handle::after {
16046
+ top: 50%;
16047
+ left: 0;
16048
+ transform: translateY(-50%);
16049
+ width: 100%;
16050
+ height: 2px;
16051
+ }
16052
+
16053
+ .\${P}-padding-control-handle::after {
16054
+ content: '';
16055
+ position: absolute;
16056
+ top: 50%;
16057
+ left: 50%;
16058
+ transform: translate(-50%, -50%);
16059
+ width: 4px;
16060
+ height: 12px;
16061
+ background: #FF5C02;
16062
+ border: 1px solid #FFFFFF;
16063
+ border-radius: 5px;
16064
+ pointer-events: none;
16065
+ box-sizing: border-box;
16066
+ }
16067
+
16068
+ .\${P}-wrapper.\${P}-type-b .\${P}-padding-control-handle::after {
16069
+ width: 12px;
16070
+ height: 4px;
16071
+ }
16072
+
16073
+ .\${P}-text-padding-lr-handle {
16074
+ background: transparent;
16075
+ }
16076
+
16077
+ .\${P}-text-padding-lr-handle::after {
16078
+ content: '';
16079
+ position: absolute;
16080
+ top: 50%;
16081
+ left: 50%;
16082
+ transform: translate(-50%, -50%);
16083
+ width: 4px;
16084
+ height: 12px;
16085
+ background: #FF5C02;
16086
+ border: 1px solid #FFFFFF;
16087
+ border-radius: 5px;
16088
+ pointer-events: none;
16089
+ box-sizing: border-box;
16090
+ }
16091
+
16092
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link,
16093
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link,
16094
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item,
16095
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item {
16096
+ transition: background-color 250ms, border-color 250ms;
16097
+ }
16098
+
16099
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link .\${P}-list-col-title,
16100
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link .\${P}-list-col-title,
16101
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-label,
16102
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-label {
16103
+ transition: color 250ms;
16104
+ }
16105
+
16106
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link:hover,
16107
+ .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link,
16108
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item:hover,
16109
+ .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item {
16110
+ background: var(--\${P}-background-hover-color);
16111
+ }
16112
+
16113
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item-has-link:hover,
16114
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item:has(+ .\${P}-list-item-has-link:hover),
16115
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item:has(+ .\${P}-cut-item:hover),
16116
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link,
16117
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-cut-item:hover,
16118
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item,
16119
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover,
16120
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item:has(+ .\${P}-list-item-has-link:hover),
16121
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item:has(+ .\${P}-cut-item:hover),
16122
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link,
16123
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-cut-item:hover,
16124
+ .\${P}-wrapper.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item {
16125
+ border-bottom-color: var(--\${P}-divider-hover-color);
16126
+ }
16127
+
16128
+ .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-default .\${P}-list-item-has-link:hover:first-child,
16129
+ .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link:first-child,
16130
+ .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover:first-child,
16131
+ .\${P}-wrapper.\${P}-divider-top:not(.\${P}-divider-bottom).\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link:first-child {
16132
+ border-top-color: var(--\${P}-divider-hover-color);
16133
+ }
16134
+
16135
+ .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-default .\${P}-list-item-has-link:hover:first-child,
16136
+ .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link:first-child,
16137
+ .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover:first-child,
16138
+ .\${P}-wrapper.\${P}-divider-top.\${P}-divider-bottom.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link:first-child {
16139
+ border-top-color: var(--\${P}-divider-hover-color);
16140
+ }
16141
+
16142
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-list-item-has-link:hover .\${P}-list-col-title,
16143
+ .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-list-item-has-link .\${P}-list-col-title,
16144
+ .\${P}-wrapper.\${P}-entry-hover-default .\${P}-cut-item:hover .\${P}-cut-label,
16145
+ .\${P}-wrapper.\${P}-entry-hover-default.\${P}-state-hover .\${P}-cut-item .\${P}-cut-label,
16146
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover .\${P}-list-col-title,
16147
+ .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link .\${P}-list-col-title,
16148
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item:hover .\${P}-cut-label,
16149
+ .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item .\${P}-cut-label {
16150
+ color: var(--\${P}-text-hover-color);
16151
+ }
16152
+
16153
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link::before,
16154
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item::before {
16155
+ content: '';
16156
+ position: absolute;
16157
+ inset: 0;
16158
+ background: var(--\${P}-background-hover-color);
16159
+ transform: scaleY(0);
16160
+ transform-origin: center center;
16161
+ transition: transform 250ms;
16162
+ z-index: 0;
16163
+ pointer-events: none;
16164
+ }
16165
+
16166
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-col,
16167
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-label {
16168
+ position: relative;
16169
+ z-index: 1;
16170
+ }
16171
+
16172
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-list-item-has-link:hover::before,
16173
+ .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-list-item-has-link::before,
16174
+ .\${P}-wrapper.\${P}-entry-hover-blinds .\${P}-cut-item:hover::before,
16175
+ .\${P}-wrapper.\${P}-entry-hover-blinds.\${P}-state-hover .\${P}-cut-item::before {
16176
+ transform: scaleY(1);
16177
+ }
16178
+
16179
+ .\${P}-cut-item {
16180
+ display: flex;
16181
+ align-items: center;
16182
+ justify-content: center;
16183
+ width: 100%;
16184
+ overflow: visible;
16185
+ position: relative;
16186
+ z-index: 3;
16187
+ box-sizing: border-box;
16188
+ user-select: none;
16189
+ background: var(--\${P}-background-color);
16190
+ cursor: pointer;
16191
+ padding: 0;
16192
+ border: none;
16193
+ font: inherit;
16194
+ text-align: inherit;
16195
+ appearance: none;
16196
+ -webkit-appearance: none;
16197
+ }
16198
+
16199
+ .\${P}-cut-item .\${P}-list-cols-row {
16200
+ flex: 1;
16201
+ min-height: 100%;
16202
+ align-items: center;
16203
+ }
16204
+
16205
+ .\${P}-wrapper.\${P}-divider-bottom .\${P}-cut-item {
16206
+ border-bottom-style: solid;
16207
+ border-bottom-color: var(--\${P}-divider-color);
16208
+ }
16209
+
16210
+ .\${P}-cut-label {
16211
+ display: block;
16212
+ position: relative;
16213
+ z-index: 1;
16214
+ margin: 0;
16215
+ color: var(--\${P}-text-color);
16216
+ white-space: pre-wrap;
16217
+ overflow-wrap: anywhere;
16218
+ word-break: break-word;
16219
+ }
16220
+ \`;
16221
+ }
16222
+
16223
+ export const COLUMN_CONTENT_KEYS = [
16224
+ 'AColumn',
16225
+ 'BColumnWidth',
16226
+ 'CColumnWidth',
16227
+ 'DColumnWidth',
16228
+ 'EColumnWidth',
16229
+ ] as const;
16230
+
16231
+ export const COLUMN_TEXT_PREFIXES = [
16232
+ 'AColumn',
16233
+ 'BColumn',
16234
+ 'CColumn',
16235
+ 'DColumn',
16236
+ 'EColumn',
16237
+ ] as const;
16238
+
16239
+ export const CUT_LABEL_TEXT_PREFIX = 'cutLabel' as const;
16240
+
16241
+ export const LIST_TEXT_STYLE_PREFIXES = [
16242
+ ...COLUMN_TEXT_PREFIXES,
16243
+ CUT_LABEL_TEXT_PREFIX,
16244
+ ] as const;
16245
+
16246
+ export type ListTextStylePrefix = typeof LIST_TEXT_STYLE_PREFIXES[number];
16247
+
16248
+ export const LIST_COLUMN_LETTERS = ['A', 'B', 'C', 'D', 'E'] as const;
16249
+
16250
+ export function getListColumnVerticalAlignSettingKey(columnLetter: string): string {
16251
+ return \`\${columnLetter}ColumnVerticalAlign\`;
16252
+ }
16253
+
16254
+ export const COLUMN_VALIGN_BASIC_OPTIONS = ['Top', 'Center', 'Bottom'] as const;
16255
+
16256
+ export function isBaselineAnchorColumnVerticalAlign(value: string | undefined): boolean {
16257
+ const raw = String(value ?? 'Top').trim();
16258
+ if (raw.toLowerCase().startsWith('baseline')) {
16259
+ return false;
16260
+ }
16261
+ return raw === 'Top' || raw === 'Center' || raw === 'Bottom';
16262
+ }
16263
+
16264
+ export function parseBaselineAnchorLetter(value: string | undefined): string | null {
16265
+ const raw = String(value ?? '').trim();
16266
+ if (!raw.toLowerCase().startsWith('baseline')) {
16267
+ return null;
16268
+ }
16269
+ const anchorLetter = raw.slice(-1).toUpperCase();
16270
+ return LIST_COLUMN_LETTERS.includes(anchorLetter as typeof LIST_COLUMN_LETTERS[number])
16271
+ ? anchorLetter
16272
+ : null;
16273
+ }
16274
+
16275
+ export function isValidColumnBaselineVAlign(
16276
+ value: string | undefined,
16277
+ forColumnLetter: string,
16278
+ settings: ListSettings,
16279
+ ): boolean {
16280
+ const anchorLetter = parseBaselineAnchorLetter(value);
16281
+ if (!anchorLetter) {
16282
+ return true;
16283
+ }
16284
+ if (anchorLetter === forColumnLetter) {
16285
+ return false;
16286
+ }
16287
+ return isBaselineAnchorColumnVerticalAlign(settings[getListColumnVerticalAlignSettingKey(anchorLetter) as ListColumnVerticalAlignKey]);
16288
+ }
16289
+
16290
+ export function getColumnVerticalAlignOptionsForLetter(
16291
+ columnLetter: string,
16292
+ settings: ListSettings,
16293
+ ): string[] {
16294
+ const baselineOptions = LIST_COLUMN_LETTERS
16295
+ .filter((letter) => letter !== columnLetter)
16296
+ .filter((letter) => isBaselineAnchorColumnVerticalAlign(settings[getListColumnVerticalAlignSettingKey(letter) as ListColumnVerticalAlignKey]))
16297
+ .map((letter) => \`Baseline \${letter}\`);
16298
+
16299
+ return [...COLUMN_VALIGN_BASIC_OPTIONS, ...baselineOptions];
16300
+ }
16301
+
16302
+ type ColumnVerticalAlign =
16303
+ | { kind: 'top' | 'center' | 'bottom' }
16304
+ | { kind: 'baseline'; anchorLetter: string };
16305
+
16306
+ function parseColumnVerticalAlign(value: string | undefined): ColumnVerticalAlign {
16307
+ const raw = String(value ?? 'Top').trim();
16308
+ if (raw.toLowerCase().startsWith('baseline')) {
16309
+ const anchorLetter = raw.slice(-1).toUpperCase();
16310
+ if (LIST_COLUMN_LETTERS.includes(anchorLetter as typeof LIST_COLUMN_LETTERS[number])) {
16311
+ return { kind: 'baseline', anchorLetter };
16312
+ }
16313
+ return { kind: 'top' };
16314
+ }
16315
+ if (raw === 'Center') return { kind: 'center' };
16316
+ if (raw === 'Bottom') return { kind: 'bottom' };
16317
+ return { kind: 'top' };
16318
+ }
16319
+
16320
+ function resolveColumnVerticalAlign(
16321
+ value: string | undefined,
16322
+ settings: ListSettings,
16323
+ columnLetter: string,
16324
+ ): ColumnVerticalAlign {
16325
+ if (isActiveBaselineVAlign(value, settings, columnLetter)) {
16326
+ return parseColumnVerticalAlign(value);
16327
+ }
16328
+
16329
+ const parsed = parseColumnVerticalAlign(value);
16330
+ if (parsed.kind === 'baseline') {
16331
+ return { kind: 'top' };
16332
+ }
16333
+
16334
+ return parsed;
16335
+ }
16336
+
16337
+ function isActiveBaselineVAlign(
16338
+ value: string | undefined,
16339
+ settings: ListSettings,
16340
+ forColumnLetter: string,
16341
+ ): boolean {
16342
+ if (!isValidColumnBaselineVAlign(value, forColumnLetter, settings)) {
16343
+ return false;
16344
+ }
16345
+ return parseColumnVerticalAlign(value).kind === 'baseline';
16346
+ }
16347
+
16348
+ function getListColumnVerticalAlignSanitizeUpdates(
16349
+ settings: ListSettings,
16350
+ ): ListColumnVerticalAlignUpdates | null {
16351
+ if (settings.type === 'B') {
16352
+ return null;
16353
+ }
16354
+
16355
+ const updates: ListColumnVerticalAlignUpdates = {};
16356
+ let hasUpdates = false;
16357
+
16358
+ for (const letter of LIST_COLUMN_LETTERS) {
16359
+ const key = getListColumnVerticalAlignSettingKey(letter) as ListColumnVerticalAlignKey;
16360
+ const value = settings[key];
16361
+ if (!isValidColumnBaselineVAlign(value, letter, settings)) {
16362
+ updates[key] = 'Top';
16363
+ hasUpdates = true;
16364
+ }
16365
+ }
16366
+
16367
+ return hasUpdates ? updates : null;
16368
+ }
16369
+
16370
+ function vAlignToTitleStyle(
16371
+ kind: ColumnVerticalAlign['kind'],
16372
+ ): React.CSSProperties {
16373
+ if (kind === 'center') {
16374
+ return { marginTop: 'auto', marginBottom: 'auto' };
16375
+ }
16376
+ if (kind === 'bottom') {
16377
+ return { marginTop: 'auto' };
16378
+ }
16379
+ return {};
16380
+ }
16381
+
16382
+ function getFirstLineBaselineOffsetInTitle(
16383
+ titleEl: HTMLElement,
16384
+ probeClassName: string,
16385
+ ): number {
16386
+ const probe = document.createElement('i');
16387
+ probe.className = probeClassName;
16388
+ probe.setAttribute('aria-hidden', 'true');
16389
+ titleEl.prepend(probe);
16390
+
16391
+ const { top: titleTop } = titleEl.getBoundingClientRect();
16392
+ const { bottom: probeBottom } = probe.getBoundingClientRect();
16393
+ const baselineOffset = probeBottom - titleTop;
16394
+ probe.remove();
16395
+
16396
+ return baselineOffset;
16397
+ }
16398
+
16399
+ function measureColumnFirstLineBaselineOffset(
16400
+ info: {
16401
+ titleEl: HTMLElement | null;
16402
+ kind: string;
16403
+ },
16404
+ rowTop: number,
16405
+ listColClassName: string,
16406
+ probeClassName: string,
16407
+ ): number {
16408
+ const titleEl = info.titleEl;
16409
+ if (!titleEl) return 0;
16410
+
16411
+ const listCol = titleEl.closest<HTMLElement>(\`.\${listColClassName}\`);
16412
+ if (!listCol) return 0;
16413
+
16414
+ const baselineInTitle = getFirstLineBaselineOffsetInTitle(titleEl, probeClassName);
16415
+
16416
+ if (info.kind === 'baseline') {
16417
+ return titleEl.getBoundingClientRect().top - rowTop + baselineInTitle;
16418
+ }
16419
+
16420
+ const listColRect = listCol.getBoundingClientRect();
16421
+ const titleHeight = titleEl.getBoundingClientRect().height;
16422
+ let valignOffset = 0;
16423
+
16424
+ if (info.kind === 'center') {
16425
+ valignOffset = (listColRect.height - titleHeight) / 2;
16426
+ } else if (info.kind === 'bottom') {
16427
+ valignOffset = listColRect.height - titleHeight;
16428
+ }
16429
+
16430
+ return (listColRect.top - rowTop) + valignOffset + baselineInTitle;
16431
+ }
16432
+
16433
+ function syncRowListColHeights(
16434
+ rowEl: HTMLElement,
16435
+ cols: HTMLElement[],
16436
+ listColClassName: string,
16437
+ ): number {
16438
+ const rowHeight = rowEl.getBoundingClientRect().height;
16439
+ if (rowHeight <= 0) {
16440
+ return 0;
16441
+ }
16442
+
16443
+ cols.forEach((colEl) => {
16444
+ const listCol = colEl.querySelector<HTMLElement>(\`.\${listColClassName}\`);
16445
+ if (listCol) {
16446
+ listCol.style.minHeight = \`\${rowHeight}px\`;
16447
+ listCol.style.height = \`\${rowHeight}px\`;
16448
+ }
16449
+ });
16450
+
16451
+ void rowEl.offsetHeight;
16452
+ return rowHeight;
16453
+ }
16454
+
16455
+ function applyBaselineTitleShift(titleEl: HTMLElement | null, shift: number): number {
16456
+ if (!titleEl || !shift) {
16457
+ if (titleEl) {
16458
+ titleEl.style.transform = '';
16459
+ }
16460
+ return 0;
16461
+ }
16462
+
16463
+ titleEl.style.transform = \`translateY(\${shift}px)\`;
16464
+ return shift;
16465
+ }
16466
+
16467
+ const COLUMN_CONTENT_KEY_TO_TEXT_PREFIX: Record<
16468
+ typeof COLUMN_CONTENT_KEYS[number],
16469
+ typeof COLUMN_TEXT_PREFIXES[number]
16470
+ > = {
16471
+ AColumn: 'AColumn',
16472
+ BColumnWidth: 'BColumn',
16473
+ CColumnWidth: 'CColumn',
16474
+ DColumnWidth: 'DColumn',
16475
+ EColumnWidth: 'EColumn',
16476
+ };
16477
+
16478
+ export const LIST_GLOBAL_TEXT_STYLE_KEYS = [
16479
+ 'textFontFamily',
16480
+ 'textFontSettings',
16481
+ 'textFontSize',
16482
+ 'textLineHeight',
16483
+ 'textLetterSpacing',
16484
+ 'textWordSpacing',
16485
+ 'textTextAppearance',
16486
+ ] as const;
16487
+
16488
+ export type ListGlobalTextStyleKey = typeof LIST_GLOBAL_TEXT_STYLE_KEYS[number];
16489
+
16490
+ export function getListColumnTextSettingKey(
16491
+ prefix: ListTextStylePrefix,
16492
+ globalKey: ListGlobalTextStyleKey,
16493
+ ): string {
16494
+ return \`\${prefix}\${globalKey.replace(/^text/, 'Text')}\`;
16495
+ }
16496
+
16497
+ type ListTextStyleFields = {
16498
+ textFontFamily?: string;
16499
+ textFontSettings?: { fontWeight: number; fontStyle: string };
16500
+ textFontSize?: number;
16501
+ textLineHeight?: number;
16502
+ textLetterSpacing?: number;
16503
+ textWordSpacing?: number;
16504
+ textTextAppearance?: TextStyles['textAppearance'];
16505
+ textColor?: string;
16506
+ };
16507
+
16508
+ type ResolvedListTextFields = {
16509
+ textFontFamily: string;
16510
+ textFontSettings: { fontWeight: number; fontStyle: string };
16511
+ textFontSize?: number;
16512
+ textLineHeight?: number;
16513
+ textLetterSpacing: number;
16514
+ textWordSpacing: number;
16515
+ textTextAppearance?: TextStyles['textAppearance'];
16516
+ textColor?: string;
16517
+ };
16518
+
16519
+ function resolveListGlobalTextFields(
16520
+ settings: ListTextStyleFields,
16521
+ ): ResolvedListTextFields {
16522
+ return {
16523
+ textFontFamily: settings.textFontFamily ?? 'Arial',
16524
+ textFontSettings: settings.textFontSettings ?? {
16525
+ fontWeight: 400,
16526
+ fontStyle: 'normal',
16527
+ },
16528
+ textFontSize: settings.textFontSize,
16529
+ textLineHeight: settings.textLineHeight,
16530
+ textLetterSpacing: settings.textLetterSpacing ?? 0,
16531
+ textWordSpacing: settings.textWordSpacing ?? 0,
16532
+ textTextAppearance: settings.textTextAppearance,
16533
+ textColor: settings.textColor,
16534
+ };
16535
+ }
16536
+
16537
+ function resolveListColumnTextFields(
16538
+ settings: ListSettings,
16539
+ textPrefix: ListTextStylePrefix,
16540
+ ): ResolvedListTextFields {
16541
+ const read = <K extends ListGlobalTextStyleKey>(globalKey: K) => {
16542
+ const columnKey = getListColumnTextSettingKey(textPrefix, globalKey);
16543
+ const columnValue = settings[columnKey as keyof ListSettings];
16544
+ if (columnValue !== undefined) {
16545
+ return columnValue as ListTextStyleFields[K];
16546
+ }
16547
+ return settings[globalKey];
16548
+ };
16549
+
16550
+ return {
16551
+ textFontFamily: (read('textFontFamily') as string | undefined) ?? 'Arial',
16552
+ textFontSettings: (read('textFontSettings') as ListTextStyleFields['textFontSettings']) ?? {
16553
+ fontWeight: 400,
16554
+ fontStyle: 'normal',
16555
+ },
16556
+ textFontSize: read('textFontSize') as number | undefined,
16557
+ textLineHeight: read('textLineHeight') as number | undefined,
16558
+ textLetterSpacing: (read('textLetterSpacing') as number | undefined) ?? 0,
16559
+ textWordSpacing: (read('textWordSpacing') as number | undefined) ?? 0,
16560
+ textTextAppearance: read('textTextAppearance') as ListTextStyleFields['textTextAppearance'],
16561
+ textColor: settings.textColor,
16562
+ };
16563
+ }
16564
+
16565
+ function listColumnTextFieldsToCss(
16566
+ fields: ResolvedListTextFields,
16567
+ isEditor?: boolean,
16568
+ ): React.CSSProperties {
16569
+ const resolvedTextStyle: TextStyles = {
16570
+ fontSettings: {
16571
+ fontFamily: fields.textFontFamily,
16572
+ fontWeight: fields.textFontSettings?.fontWeight ?? 400,
16573
+ fontStyle: fields.textFontSettings?.fontStyle ?? 'normal',
16574
+ },
16575
+ fontSize: fields.textFontSize ?? 0.01,
16576
+ lineHeight: fields.textLineHeight,
16577
+ letterSpacing: fields.textLetterSpacing,
16578
+ wordSpacing: fields.textWordSpacing,
16579
+ textAppearance: fields.textTextAppearance,
16580
+ color: fields.textColor ?? '#767676',
16581
+ };
16582
+
16583
+ return omitTextColors(textStylesToCss(resolvedTextStyle, isEditor));
16584
+ }
16585
+
16586
+ function getListColumnTitleClassName(
16587
+ settings: ListSettings,
16588
+ prefix: ListTextStylePrefix,
16589
+ baseClassName: string,
16590
+ tightLeadingClassName: string,
16591
+ ): string {
16592
+ const fields = resolveListColumnTextFields(settings, prefix);
16593
+ const fontSize = fields.textFontSize ?? 0.01;
16594
+ const lineHeight = fields.textLineHeight;
16595
+ const needsTightLeading = lineHeight !== undefined && lineHeight < fontSize;
16596
+
16597
+ return needsTightLeading
16598
+ ? \`\${baseClassName} \${tightLeadingClassName}\`
16599
+ : baseClassName;
16600
+ }
16601
+
16602
+ function getListColumnTitleVars(
16603
+ settings: ListSettings,
16604
+ prefix: ListTextStylePrefix,
16605
+ titleVarPrefix: string,
16606
+ isEditor?: boolean,
16607
+ ): React.CSSProperties {
16608
+ const fields = resolveListColumnTextFields(settings, prefix);
16609
+ const fontSize = fields.textFontSize ?? 0.01;
16610
+ const lineHeight = fields.textLineHeight;
16611
+
16612
+ if (lineHeight === undefined || lineHeight >= fontSize) {
16613
+ return {};
16614
+ }
16615
+
16616
+ return {
16617
+ [\`--\${titleVarPrefix}-title-leading-gap\`]: scalingValue((fontSize - lineHeight) / 2, isEditor),
16618
+ } as React.CSSProperties;
16619
+ }
16620
+
16621
+ function getListGlobalTextSyncUpdates(
16622
+ nextSettings: ListSettings,
16623
+ prevSettings: ListSettings,
16624
+ ): ListColumnTextStyleSyncUpdates | null {
16625
+ const updates: ListColumnTextStyleSyncUpdates = {};
16626
+ let hasChanges = false;
16627
+
16628
+ for (const globalKey of LIST_GLOBAL_TEXT_STYLE_KEYS) {
16629
+ if (nextSettings[globalKey] === prevSettings[globalKey]) {
16630
+ continue;
16631
+ }
16632
+ if (nextSettings[globalKey] === undefined) {
16633
+ continue;
16634
+ }
16635
+
16636
+ hasChanges = true;
16637
+ for (const prefix of LIST_TEXT_STYLE_PREFIXES) {
16638
+ Object.assign(updates, {
16639
+ [getListColumnTextSettingKey(prefix, globalKey)]: nextSettings[globalKey],
16640
+ });
16641
+ }
16642
+ }
16643
+
16644
+ return hasChanges ? updates : null;
16645
+ }
16646
+
16647
+ const COLUMN_WIDTH_KEYS = [
16648
+ 'AColumnWidth',
16649
+ 'BColumnWidth',
16650
+ 'CColumnWidth',
16651
+ 'DColumnWidth',
16652
+ 'EColumnWidth',
16653
+ ] as const;
16654
+
16655
+ const COLUMN_PADDING_LEFT_KEYS = [
16656
+ 'AColumnPaddingLeft',
16657
+ 'BColumnPaddingLeft',
16658
+ 'CColumnPaddingLeft',
16659
+ 'DColumnPaddingLeft',
16660
+ 'EColumnPaddingLeft',
16661
+ ] as const;
16662
+
16663
+ const COLUMN_PADDING_RIGHT_KEYS = [
16664
+ 'AColumnPaddingRight',
16665
+ 'BColumnPaddingRight',
16666
+ 'CColumnPaddingRight',
16667
+ 'DColumnPaddingRight',
16668
+ 'EColumnPaddingRight',
16669
+ ] as const;
16670
+
16671
+ const COLUMN_PADDING_BOTTOM_KEYS = [
16672
+ 'AColumnPaddingBottom',
16673
+ 'BColumnPaddingBottom',
16674
+ 'CColumnPaddingBottom',
16675
+ 'DColumnPaddingBottom',
16676
+ 'EColumnPaddingBottom',
16677
+ ] as const;
16678
+
16679
+ type ColumnWidthKey = typeof COLUMN_WIDTH_KEYS[number];
16680
+ type ColumnPaddingLeftKey = typeof COLUMN_PADDING_LEFT_KEYS[number];
16681
+ type ColumnPaddingRightKey = typeof COLUMN_PADDING_RIGHT_KEYS[number];
16682
+ type ColumnPaddingBottomKey = typeof COLUMN_PADDING_BOTTOM_KEYS[number];
16683
+
16684
+ type ListColumnPaddingUpdates = {
16685
+ AColumnPaddingLeft?: number;
16686
+ AColumnPaddingRight?: number;
16687
+ BColumnPaddingLeft?: number;
16688
+ BColumnPaddingRight?: number;
16689
+ CColumnPaddingLeft?: number;
16690
+ CColumnPaddingRight?: number;
16691
+ DColumnPaddingLeft?: number;
16692
+ DColumnPaddingRight?: number;
16693
+ EColumnPaddingLeft?: number;
16694
+ EColumnPaddingRight?: number;
16695
+ };
16696
+
16697
+ type ListColumnWidthUpdates = {
16698
+ AColumnWidth?: number;
16699
+ BColumnWidth?: number;
16700
+ CColumnWidth?: number;
16701
+ DColumnWidth?: number;
16702
+ EColumnWidth?: number;
16703
+ };
16704
+
16705
+ type ListItemColumn = {
16706
+ key: string;
16707
+ textPrefix: typeof COLUMN_TEXT_PREFIXES[number];
16708
+ widthKey: ColumnWidthKey;
16709
+ paddingLeftKey: ColumnPaddingLeftKey;
16710
+ paddingRightKey: ColumnPaddingRightKey;
16711
+ paddingBottomKey: ColumnPaddingBottomKey;
16712
+ width: number;
16713
+ paddingLeft: number;
16714
+ paddingRight: number;
16715
+ paddingBottom: number;
16716
+ };
16717
+
16718
+ type ColorKeys =
16719
+ | 'textColor'
16720
+ | 'backgroundColor'
16721
+ | 'dividerColor'
16722
+ | 'textHoverColor'
16723
+ | 'backgroundHoverColor'
16724
+ | 'dividerHoverColor';
16725
+
16726
+ const COLOR_VAR_MAP: Record<ColorKeys, string> = {
16727
+ textColor: 'text-color',
16728
+ backgroundColor: 'background-color',
16729
+ dividerColor: 'divider-color',
16730
+ textHoverColor: 'text-hover-color',
16731
+ backgroundHoverColor: 'background-hover-color',
16732
+ dividerHoverColor: 'divider-hover-color',
16733
+ };
16734
+
16735
+ const STATE_KEYS = ['hover', 'focus', 'filled', 'success', 'error'] as const;
16736
+
16737
+ const COL_RESIZE_HANDLE_WIDTH = 0.004;
16738
+ const COL_PADDING_HANDLE_WIDTH = 0.004;
16739
+ const MIN_COLUMN_WIDTH_PX = 50;
16740
+ const ARTICLE_DESIGN_WIDTH = 1440;
16741
+ const MIN_COLUMN_WIDTH = MIN_COLUMN_WIDTH_PX / ARTICLE_DESIGN_WIDTH;
16742
+
16743
+ export function getListMinColumnWidth(designWidthPx?: number): number {
16744
+ const designWidth = typeof designWidthPx === 'number' && designWidthPx > 0
16745
+ ? designWidthPx
16746
+ : ARTICLE_DESIGN_WIDTH;
16747
+
16748
+ return MIN_COLUMN_WIDTH_PX / designWidth;
16749
+ }
16750
+
16751
+ function getEditorDesignWidth(element: HTMLElement | null | undefined): number {
16752
+ let el = element ?? null;
16753
+
16754
+ while (el) {
16755
+ const inline = el.style.getPropertyValue('--cntrl-article-width').trim();
16756
+ if (inline) {
16757
+ const px = parseFloat(inline);
16758
+ if (Number.isFinite(px) && px > 0) {
16759
+ return px;
16760
+ }
16761
+ }
16762
+
16763
+ const computed = getComputedStyle(el).getPropertyValue('--cntrl-article-width').trim();
16764
+ if (computed) {
16765
+ const px = parseFloat(computed);
16766
+ if (Number.isFinite(px) && px > 0) {
16767
+ return px;
16768
+ }
16769
+ }
16770
+
16771
+ el = el.parentElement;
16772
+ }
16773
+
16774
+ return ARTICLE_DESIGN_WIDTH;
16775
+ }
16776
+
16777
+ const DEFAULT_COLUMN_WIDTHS: Record<ColumnWidthKey, number> = {
16778
+ AColumnWidth: 0.02,
16779
+ BColumnWidth: 0.02,
16780
+ CColumnWidth: 0.02,
16781
+ DColumnWidth: 0.02,
16782
+ EColumnWidth: 0.02,
16783
+ };
16784
+
16785
+ export function getListEffectiveContentWidth(
16786
+ settings: ListSettings,
16787
+ ): number {
16788
+ const wrapperWidth = typeof settings.wrapperWidth === 'number' ? settings.wrapperWidth : 1;
16789
+
16790
+ return Math.max(0, wrapperWidth);
16791
+ }
16792
+
16793
+ export function getEqualListColumnWidthUpdates(
16794
+ columns: number,
16795
+ contentWidth: number = 1,
16796
+ ): Record<ColumnWidthKey, number> {
16797
+ const equalColumnWidth = contentWidth / columns;
16798
+ return Object.fromEntries(
16799
+ COLUMN_WIDTH_KEYS.map((key) => [key, equalColumnWidth]),
16800
+ ) as Record<ColumnWidthKey, number>;
16801
+ }
16802
+
16803
+ function getResetListColumnPaddingUpdates(): Record<
16804
+ ColumnPaddingLeftKey | ColumnPaddingRightKey,
16805
+ number
16806
+ > {
16807
+ return Object.fromEntries([
16808
+ ...COLUMN_PADDING_LEFT_KEYS.map((key) => [key, 0]),
16809
+ ...COLUMN_PADDING_RIGHT_KEYS.map((key) => [key, 0]),
16810
+ ]) as Record<ColumnPaddingLeftKey | ColumnPaddingRightKey, number>;
16811
+ }
16812
+
16813
+ function getResetListColumnPaddingBottomUpdates(): Record<ColumnPaddingBottomKey, number> {
16814
+ return Object.fromEntries(
16815
+ COLUMN_PADDING_BOTTOM_KEYS.map((key) => [key, 0]),
16816
+ ) as Record<ColumnPaddingBottomKey, number>;
16817
+ }
16818
+
16819
+ function getStoredColumnWidths(
16820
+ settings: ListSettings,
16821
+ ): Record<ColumnWidthKey, number> {
16822
+ return Object.fromEntries(
16823
+ COLUMN_WIDTH_KEYS.map((key) => [
16824
+ key,
16825
+ typeof settings[key] === 'number'
16826
+ ? settings[key] as number
16827
+ : DEFAULT_COLUMN_WIDTHS[key],
16828
+ ]),
16829
+ ) as Record<ColumnWidthKey, number>;
16830
+ }
16831
+
16832
+ export function resolveListColumnPadding(
16833
+ columnWidth: number,
16834
+ paddingLeft: number,
16835
+ paddingRight: number,
16836
+ ): { paddingLeft: number; paddingRight: number } {
16837
+ const maxTotalPadding = columnWidth - MIN_COLUMN_WIDTH;
16838
+ const totalPadding = paddingLeft + paddingRight;
16839
+
16840
+ if (totalPadding <= 0 || totalPadding <= maxTotalPadding) {
16841
+ return { paddingLeft, paddingRight };
16842
+ }
16843
+
16844
+ if (maxTotalPadding <= 0) {
16845
+ return { paddingLeft: 0, paddingRight: 0 };
16846
+ }
16847
+
16848
+ const scale = maxTotalPadding / totalPadding;
16849
+
16850
+ return {
16851
+ paddingLeft: paddingLeft * scale,
16852
+ paddingRight: paddingRight * scale,
16853
+ };
16854
+ }
16855
+
16856
+ export function getEffectiveListColumnWidths(
16857
+ columns: number,
16858
+ wrapperWidth: number,
16859
+ storedWidths: Record<ColumnWidthKey, number>,
16860
+ ): number[] {
16861
+ const resolvedWidths = resolveListColumnWidths(columns, wrapperWidth, storedWidths);
16862
+
16863
+ if (columns <= 0) {
16864
+ return [];
16865
+ }
16866
+
16867
+ const sumFixed = resolvedWidths.slice(0, columns - 1).reduce((sum, width) => sum + width, 0);
16868
+
16869
+ return [
16870
+ ...resolvedWidths.slice(0, columns - 1),
16871
+ Math.max(0, wrapperWidth - sumFixed),
16872
+ ];
16873
+ }
16874
+
16875
+ function getListColumnPaddingUpdates(
16876
+ columns: number,
16877
+ effectiveWidths: number[],
16878
+ settings: ListSettings,
16879
+ ): ListColumnPaddingUpdates {
16880
+ const updates: ListColumnPaddingUpdates = {};
16881
+
16882
+ for (let index = 0; index < columns; index += 1) {
16883
+ const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];
16884
+ const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];
16885
+ const storedPaddingLeft = typeof settings[paddingLeftKey] === 'number'
16886
+ ? settings[paddingLeftKey] as number
16887
+ : 0;
16888
+ const storedPaddingRight = typeof settings[paddingRightKey] === 'number'
16889
+ ? settings[paddingRightKey] as number
16890
+ : 0;
16891
+ const resolvedPadding = resolveListColumnPadding(
16892
+ effectiveWidths[index] ?? 0,
16893
+ storedPaddingLeft,
16894
+ storedPaddingRight,
16895
+ );
16896
+
16897
+ if (resolvedPadding.paddingLeft !== storedPaddingLeft) {
16898
+ updates[paddingLeftKey] = resolvedPadding.paddingLeft;
16899
+ }
16900
+
16901
+ if (resolvedPadding.paddingRight !== storedPaddingRight) {
16902
+ updates[paddingRightKey] = resolvedPadding.paddingRight;
16903
+ }
16904
+ }
16905
+
16906
+ return updates;
16907
+ }
16908
+
16909
+ export function resolveListColumnWidths(
16910
+ columns: number,
16911
+ wrapperWidth: number,
16912
+ storedWidths: Record<ColumnWidthKey, number>,
16913
+ ): number[] {
16914
+ if (columns <= 0) {
16915
+ return [];
16916
+ }
16917
+
16918
+ const widths = COLUMN_WIDTH_KEYS.slice(0, columns).map(
16919
+ (key) => storedWidths[key],
16920
+ );
16921
+
16922
+ if (columns === 1) {
16923
+ return widths;
16924
+ }
16925
+
16926
+ const fixedWidths = widths.slice(0, columns - 1);
16927
+ const fixedSum = fixedWidths.reduce((sum, width) => sum + width, 0);
16928
+ const minTotalWidth = fixedSum + MIN_COLUMN_WIDTH;
16929
+
16930
+ if (wrapperWidth >= minTotalWidth) {
16931
+ return widths;
16932
+ }
16933
+
16934
+ const resolvedFixedWidths = [...fixedWidths];
16935
+ let overflow = minTotalWidth - wrapperWidth;
16936
+
16937
+ for (let index = resolvedFixedWidths.length - 1; index >= 0 && overflow > 0; index -= 1) {
16938
+ const shrinkable = resolvedFixedWidths[index] - MIN_COLUMN_WIDTH;
16939
+ if (shrinkable <= 0) {
16940
+ continue;
16941
+ }
16942
+
16943
+ const shrinkAmount = Math.min(overflow, shrinkable);
16944
+ resolvedFixedWidths[index] -= shrinkAmount;
16945
+ overflow -= shrinkAmount;
16946
+ }
16947
+
16948
+ return [...resolvedFixedWidths, widths[columns - 1]];
16949
+ }
16950
+
16951
+ function getListColumnWidthUpdatesForWrapperWidth(
16952
+ columns: number,
16953
+ wrapperWidth: number,
16954
+ storedWidths: Record<ColumnWidthKey, number>,
16955
+ ): ListColumnWidthUpdates {
16956
+ if (columns <= 1) {
16957
+ return {};
16958
+ }
16959
+
16960
+ const resolvedWidths = resolveListColumnWidths(columns, wrapperWidth, storedWidths);
16961
+ const updates: ListColumnWidthUpdates = {};
16962
+
16963
+ for (let index = 0; index < columns - 1; index += 1) {
16964
+ const key = COLUMN_WIDTH_KEYS[index];
16965
+ if (resolvedWidths[index] !== storedWidths[key]) {
16966
+ updates[key] = resolvedWidths[index];
16967
+ }
16968
+ }
16969
+
16970
+ return updates;
16971
+ }
16972
+
16973
+ function getColumnsOrder(settings: ListSettings): string[] {
16974
+ if (Array.isArray(settings.columnsOrder) && settings.columnsOrder.length > 0) {
16975
+ return settings.columnsOrder as string[];
16976
+ }
16977
+
16978
+ return [...COLUMN_CONTENT_KEYS];
16979
+ }
16980
+
16981
+ function areStringArraysEqual(left: string[], right: string[]): boolean {
16982
+ if (left.length !== right.length) {
16983
+ return false;
16984
+ }
16985
+
16986
+ return left.every((value, index) => value === right[index]);
16987
+ }
16988
+
16989
+ function getColumnLayoutUpdatesForOrderChange(
16990
+ nextOrder: string[],
16991
+ prevOrder: string[],
16992
+ prevSettings: ListSettings,
16993
+ columns: number,
16994
+ ): Record<string, number> {
16995
+ const count = Math.min(columns, nextOrder.length, COLUMN_WIDTH_KEYS.length);
16996
+ const updates: Record<string, number> = {};
16997
+
16998
+ for (let index = 0; index < count; index += 1) {
16999
+ const contentKey = nextOrder[index];
17000
+ const prevSlotIndex = prevOrder.indexOf(contentKey);
17001
+
17002
+ if (prevSlotIndex === -1) {
17003
+ continue;
17004
+ }
17005
+
17006
+ const prevWidthKey = COLUMN_WIDTH_KEYS[prevSlotIndex];
17007
+ const prevPaddingLeftKey = COLUMN_PADDING_LEFT_KEYS[prevSlotIndex];
17008
+ const prevPaddingRightKey = COLUMN_PADDING_RIGHT_KEYS[prevSlotIndex];
17009
+ const prevPaddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[prevSlotIndex];
17010
+ const widthKey = COLUMN_WIDTH_KEYS[index];
17011
+ const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];
17012
+ const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];
17013
+ const paddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[index];
17014
+
17015
+ const prevWidth = prevSettings[prevWidthKey];
17016
+ const prevPaddingLeft = prevSettings[prevPaddingLeftKey];
17017
+ const prevPaddingRight = prevSettings[prevPaddingRightKey];
17018
+ const prevPaddingBottom = prevSettings[prevPaddingBottomKey];
17019
+
17020
+ if (typeof prevWidth === 'number') {
17021
+ updates[widthKey] = prevWidth;
17022
+ }
17023
+
17024
+ if (typeof prevPaddingLeft === 'number') {
17025
+ updates[paddingLeftKey] = prevPaddingLeft;
17026
+ }
17027
+
17028
+ if (typeof prevPaddingRight === 'number') {
17029
+ updates[paddingRightKey] = prevPaddingRight;
17030
+ }
17031
+
17032
+ if (typeof prevPaddingBottom === 'number') {
17033
+ updates[paddingBottomKey] = prevPaddingBottom;
17034
+ }
17035
+ }
17036
+
17037
+ return updates;
17038
+ }
17039
+
17040
+ export function applyListSettingsChange(
17041
+ nextSettings: ListSettings,
17042
+ prevSettings: ListSettings,
17043
+ options?: { designWidth?: number },
17044
+ ): ListSettings {
17045
+ const textSyncUpdates = getListGlobalTextSyncUpdates(nextSettings, prevSettings);
17046
+ if (textSyncUpdates) {
17047
+ nextSettings = { ...nextSettings, ...textSyncUpdates };
17048
+ }
17049
+
17050
+ const valignSanitizeUpdates = getListColumnVerticalAlignSanitizeUpdates(nextSettings);
17051
+ if (valignSanitizeUpdates) {
17052
+ nextSettings = { ...nextSettings, ...valignSanitizeUpdates };
17053
+ }
17054
+
17055
+ const minColumnWidth = getListMinColumnWidth(options?.designWidth);
17056
+ const nextColumns = nextSettings.columns;
17057
+ const prevColumns = prevSettings.columns;
17058
+ const nextContentWidth = getListEffectiveContentWidth(nextSettings);
17059
+ const prevContentWidth = getListEffectiveContentWidth(prevSettings);
17060
+ const isVerticalLayout = nextSettings.type === 'B'
17061
+ || (nextSettings.type === undefined && prevSettings.type === 'B');
17062
+ const columns =
17063
+ typeof nextColumns === 'number'
17064
+ ? nextColumns
17065
+ : typeof prevColumns === 'number'
17066
+ ? prevColumns
17067
+ : COLUMN_CONTENT_KEYS.length;
17068
+
17069
+ const withColumnPaddingUpdates = (
17070
+ settings: ListSettings,
17071
+ ): ListSettings => {
17072
+ if (isVerticalLayout) {
17073
+ return settings;
17074
+ }
17075
+
17076
+ const storedWidths = getStoredColumnWidths({ ...prevSettings, ...settings });
17077
+ const contentWidth = getListEffectiveContentWidth(settings);
17078
+ const effectiveWidths = getEffectiveListColumnWidths(columns, contentWidth, storedWidths);
17079
+ const paddingUpdates = getListColumnPaddingUpdates(columns, effectiveWidths, {
17080
+ ...prevSettings,
17081
+ ...settings,
17082
+ });
17083
+
17084
+ if (Object.keys(paddingUpdates).length === 0) {
17085
+ return settings;
17086
+ }
17087
+
17088
+ return {
17089
+ ...settings,
17090
+ ...paddingUpdates,
17091
+ };
17092
+ };
17093
+
17094
+ if (typeof nextColumns === 'number' && nextColumns !== prevColumns) {
17095
+ const updates: ListSettings = {
17096
+ ...nextSettings,
17097
+ ...getEqualListColumnWidthUpdates(nextColumns, nextContentWidth),
17098
+ ...getResetListColumnPaddingUpdates(),
17099
+ };
17100
+
17101
+ if (isVerticalLayout) {
17102
+ for (const key of COLUMN_PADDING_BOTTOM_KEYS) {
17103
+ if (typeof prevSettings[key] === 'number') {
17104
+ updates[key] = prevSettings[key];
17105
+ }
17106
+ }
17107
+ } else {
17108
+ Object.assign(updates, getResetListColumnPaddingBottomUpdates());
17109
+ }
17110
+
17111
+ return updates;
17112
+ }
17113
+
17114
+ const nextOrder = getColumnsOrder(nextSettings);
17115
+ const prevOrder = getColumnsOrder(prevSettings);
17116
+
17117
+ if (!areStringArraysEqual(nextOrder, prevOrder)) {
17118
+ return withColumnPaddingUpdates({
17119
+ ...nextSettings,
17120
+ ...getColumnLayoutUpdatesForOrderChange(nextOrder, prevOrder, prevSettings, columns),
17121
+ });
17122
+ }
17123
+
17124
+ if (nextContentWidth < prevContentWidth) {
17125
+ if (typeof columns === 'number' && !isVerticalLayout) {
17126
+ const storedWidths = getStoredColumnWidths({ ...prevSettings, ...nextSettings });
17127
+
17128
+ return withColumnPaddingUpdates({
17129
+ ...nextSettings,
17130
+ ...getListColumnWidthUpdatesForWrapperWidth(columns, nextContentWidth, storedWidths),
17131
+ });
17132
+ }
17133
+ }
17134
+
17135
+ if (isVerticalLayout) {
17136
+ const storedTextPaddingLR = typeof nextSettings.textPaddingLR === 'number'
17137
+ ? nextSettings.textPaddingLR as number
17138
+ : 0;
17139
+ const maxAllowedPadding = Math.max(0, (nextContentWidth - minColumnWidth) / 2);
17140
+
17141
+ if (storedTextPaddingLR > maxAllowedPadding) {
17142
+ return { ...nextSettings, textPaddingLR: maxAllowedPadding };
17143
+ }
17144
+
17145
+ return nextSettings;
17146
+ }
17147
+
17148
+ const storedWidths = getStoredColumnWidths({ ...prevSettings, ...nextSettings });
17149
+ const prevEffectiveWidths = getEffectiveListColumnWidths(
17150
+ columns,
17151
+ prevContentWidth,
17152
+ getStoredColumnWidths(prevSettings),
17153
+ );
17154
+ const nextEffectiveWidths = getEffectiveListColumnWidths(
17155
+ columns,
17156
+ nextContentWidth,
17157
+ storedWidths,
17158
+ );
17159
+ const columnWidthDecreased = nextEffectiveWidths.some(
17160
+ (width, index) => width < (prevEffectiveWidths[index] ?? width),
17161
+ );
17162
+ const columnWidthSettingChanged = COLUMN_WIDTH_KEYS.some((key) => {
17163
+ const nextWidth = nextSettings[key];
17164
+ const prevWidth = prevSettings[key];
17165
+
17166
+ return typeof nextWidth === 'number'
17167
+ && typeof prevWidth === 'number'
17168
+ && nextWidth !== prevWidth;
17169
+ });
17170
+
17171
+ if (columnWidthDecreased || columnWidthSettingChanged) {
17172
+ return withColumnPaddingUpdates(nextSettings);
17173
+ }
17174
+
17175
+ return nextSettings;
17176
+ }
17177
+
17178
+ function getColumnMaxWidth(
17179
+ columnIndex: number,
17180
+ resolvedWidths: number[],
17181
+ storedWidths: number[],
17182
+ wrapperWidth: number,
17183
+ ): number {
17184
+ const leftWidth = resolvedWidths
17185
+ .slice(0, columnIndex)
17186
+ .reduce((sum, width) => sum + width, 0);
17187
+ const rightPreferredWidth = storedWidths
17188
+ .slice(columnIndex + 1, resolvedWidths.length - 1)
17189
+ .reduce((sum, width) => sum + width, 0);
17190
+
17191
+ return Math.max(
17192
+ MIN_COLUMN_WIDTH,
17193
+ wrapperWidth - leftWidth - rightPreferredWidth - MIN_COLUMN_WIDTH,
17194
+ );
17195
+ }
17196
+
17197
+ function randomBetween(min: number, max: number): number {
17198
+ return Math.random() * (max - min) + min;
17199
+ }
17200
+
17201
+ function getColumnWidthsFromSettings(
17202
+ settings: ListSettings,
17203
+ ): Record<ColumnWidthKey, number> {
17204
+ return Object.fromEntries(
17205
+ COLUMN_WIDTH_KEYS.map((key) => [
17206
+ key,
17207
+ typeof settings[key] === 'number' ? settings[key] as number : DEFAULT_COLUMN_WIDTHS[key],
17208
+ ]),
17209
+ ) as Record<ColumnWidthKey, number>;
17210
+ }
17211
+
17212
+ function getNumericSettingValues<K extends ColumnPaddingLeftKey | ColumnPaddingRightKey | ColumnPaddingBottomKey>(
17213
+ settings: ListSettings,
17214
+ keys: readonly K[],
17215
+ fallback = 0,
17216
+ ): Record<K, number> {
17217
+ return Object.fromEntries(
17218
+ keys.map((key) => [
17219
+ key,
17220
+ typeof settings[key] === 'number' ? settings[key] as number : fallback,
17221
+ ]),
17222
+ ) as Record<K, number>;
17223
+ }
17224
+
17225
+ function buildListColumns(
17226
+ columnContentOrder: readonly typeof COLUMN_CONTENT_KEYS[number][],
17227
+ columns: number,
17228
+ columnWidthByKey: Record<ColumnWidthKey, number>,
17229
+ columnPaddingLeftByKey: Record<ColumnPaddingLeftKey, number>,
17230
+ columnPaddingRightByKey: Record<ColumnPaddingRightKey, number>,
17231
+ columnPaddingBottomByKey: Record<ColumnPaddingBottomKey, number>,
17232
+ ): ListItemColumn[] {
17233
+ return columnContentOrder.slice(0, columns).map((key, index) => {
17234
+ const paddingLeftKey = COLUMN_PADDING_LEFT_KEYS[index];
17235
+ const paddingRightKey = COLUMN_PADDING_RIGHT_KEYS[index];
17236
+ const paddingBottomKey = COLUMN_PADDING_BOTTOM_KEYS[index];
17237
+
17238
+ return {
17239
+ key,
17240
+ textPrefix: COLUMN_CONTENT_KEY_TO_TEXT_PREFIX[key],
17241
+ widthKey: COLUMN_WIDTH_KEYS[index],
17242
+ width: columnWidthByKey[COLUMN_WIDTH_KEYS[index]],
17243
+ paddingLeftKey,
17244
+ paddingRightKey,
17245
+ paddingBottomKey,
17246
+ paddingLeft: columnPaddingLeftByKey[paddingLeftKey],
17247
+ paddingRight: columnPaddingRightByKey[paddingRightKey],
17248
+ paddingBottom: columnPaddingBottomByKey[paddingBottomKey],
17249
+ };
17250
+ });
17251
+ }
17252
+
17253
+ export function List({ settings, content, isEditor, isPreviewMode, activeEvent, layoutId, onUpdateSettings }: ListProps) {
17254
+ const { prefix: P } = useScopedStyles();
17255
+ const showControls = Boolean(isEditor && isPreviewMode);
17256
+ const {
17257
+ columns,
17258
+ type,
17259
+ wrapperWidth,
17260
+ entriesCount,
17261
+ cellMinHeight,
17262
+ dividerWidth,
17263
+ showVisibility,
17264
+ cut,
17265
+ showCut,
17266
+ cutCellMinHeight,
17267
+ cutLabel,
17268
+ imageSize,
17269
+ imageOnHover,
17270
+ entryHoverEffect,
17271
+ rowPaddingTop,
17272
+ rowPaddingBottom,
17273
+ rowPaddingTopB,
17274
+ columnsOrder,
17275
+ textPaddingLR,
17276
+ textColor,
17277
+ textFontFamily,
17278
+ textFontSettings,
17279
+ textFontSize,
17280
+ textLineHeight,
17281
+ textLetterSpacing,
17282
+ textWordSpacing,
17283
+ textTextAppearance,
17284
+ backgroundColor,
17285
+ dividerColor,
17286
+ textHoverColor,
17287
+ backgroundHoverColor,
17288
+ dividerHoverColor,
17289
+ } = settings;
17290
+
17291
+ const [visibleRowCount, setVisibleRowCount] = useState<number | undefined>(undefined);
17292
+ const [hoverImage, setHoverImage] = useState<HoverImageState | null>(null);
17293
+ const showHoverImage = imageOnHover === 'On' && (!isEditor || isPreviewMode);
17294
+ const cutEnabled = (cut ?? 0) > 0;
17295
+ const isVerticalLayout = type === 'B';
17296
+ const containerRef = useRef<HTMLDivElement>(null);
17297
+ const [designWidth, setDesignWidth] = useState(ARTICLE_DESIGN_WIDTH);
17298
+ const minColumnWidth = getListMinColumnWidth(designWidth);
17299
+
17300
+ const storedTextPaddingLRMax = Math.max(0, ((wrapperWidth ?? 0) - minColumnWidth) / 2);
17301
+ const effectiveTextPaddingLR = Math.min(textPaddingLR ?? 0, storedTextPaddingLRMax);
17302
+ const textPaddingLRHandleWidth = Math.max(effectiveTextPaddingLR, COL_PADDING_HANDLE_WIDTH);
17303
+ const textPaddingLRMaxFraction = ((wrapperWidth ?? 0) + minColumnWidth) / 2;
17304
+
17305
+ useLayoutEffect(() => {
17306
+ if (!isEditor) {
17307
+ setDesignWidth(ARTICLE_DESIGN_WIDTH);
17308
+ return;
17309
+ }
17310
+
17311
+ const syncDesignWidth = () => {
17312
+ setDesignWidth(getEditorDesignWidth(containerRef.current));
17313
+ };
17314
+
17315
+ syncDesignWidth();
17316
+
17317
+ const observed = containerRef.current;
17318
+ if (!observed) {
17319
+ return;
17320
+ }
17321
+
17322
+ const observer = new ResizeObserver(syncDesignWidth);
17323
+ observer.observe(observed);
17324
+
17325
+ let pageEl: HTMLElement | null = observed;
17326
+ while (pageEl && !pageEl.style.getPropertyValue('--cntrl-article-width')) {
17327
+ pageEl = pageEl.parentElement;
17328
+ }
17329
+ if (pageEl) {
17330
+ observer.observe(pageEl);
17331
+ }
17332
+
17333
+ return () => observer.disconnect();
17334
+ }, [isEditor, layoutId]);
17335
+
17336
+ useEffect(() => {
17337
+ setVisibleRowCount(undefined);
17338
+ }, [cut, showCut, content, entriesCount]);
17339
+
17340
+ const colorVars = buildColorVars(P, {
17341
+ textColor,
17342
+ backgroundColor,
17343
+ dividerColor,
17344
+ textHoverColor,
17345
+ backgroundHoverColor,
17346
+ dividerHoverColor
17347
+ }, COLOR_VAR_MAP, STATE_KEYS);
17348
+
17349
+ const stateClass = activeEvent && activeEvent !== 'default' ? \`\${P}-state-\${activeEvent}\` : '';
17350
+ const entryHoverClass =
17351
+ entryHoverEffect === 'Default'
17352
+ ? \`\${P}-entry-hover-default\`
17353
+ : entryHoverEffect === 'Blinds'
17354
+ ? \`\${P}-entry-hover-blinds\`
17355
+ : '';
17356
+ const wrapperStateClasses = \`\${entryHoverClass} \${stateClass}\`.trim();
17357
+ const showDividerTop = showVisibility?.[0] ?? false;
17358
+ const showDividerBottom = showVisibility?.[1] ?? false;
17359
+
17360
+ const prevSettingsRef = useRef(settings);
17361
+ const prevLayoutIdRef = useRef(layoutId);
17362
+
17363
+ useEffect(() => {
17364
+ if (!onUpdateSettings || !isEditor) {
17365
+ prevSettingsRef.current = settings;
17366
+ prevLayoutIdRef.current = layoutId;
17367
+ return;
17368
+ }
17369
+
17370
+ if (prevLayoutIdRef.current !== layoutId) {
17371
+ prevSettingsRef.current = settings;
17372
+ prevLayoutIdRef.current = layoutId;
17373
+ return;
17374
+ }
17375
+
17376
+ const prevSettings = prevSettingsRef.current;
17377
+ const updatedSettings = applyListSettingsChange(
17378
+ settings,
17379
+ prevSettings,
17380
+ { designWidth },
17381
+ );
17382
+
17383
+ prevSettingsRef.current = settings;
17384
+
17385
+ if (updatedSettings === settings) {
17386
+ return;
17387
+ }
17388
+
17389
+ onUpdateSettings(updatedSettings);
17390
+ }, [settings, onUpdateSettings, isEditor, layoutId, designWidth]);
17391
+
17392
+ const columnWidthByKey = useMemo(
17393
+ () => getColumnWidthsFromSettings(settings),
17394
+ [
17395
+ settings.AColumnWidth,
17396
+ settings.BColumnWidth,
17397
+ settings.CColumnWidth,
17398
+ settings.DColumnWidth,
17399
+ settings.EColumnWidth,
17400
+ ],
17401
+ );
17402
+
17403
+ const columnPaddingLeftByKey = useMemo(
17404
+ () => getNumericSettingValues(settings, COLUMN_PADDING_LEFT_KEYS),
17405
+ [
17406
+ settings.AColumnPaddingLeft,
17407
+ settings.BColumnPaddingLeft,
17408
+ settings.CColumnPaddingLeft,
17409
+ settings.DColumnPaddingLeft,
17410
+ settings.EColumnPaddingLeft,
17411
+ ],
17412
+ );
17413
+
17414
+ const columnPaddingRightByKey = useMemo(
17415
+ () => getNumericSettingValues(settings, COLUMN_PADDING_RIGHT_KEYS),
17416
+ [
17417
+ settings.AColumnPaddingRight,
17418
+ settings.BColumnPaddingRight,
17419
+ settings.CColumnPaddingRight,
17420
+ settings.DColumnPaddingRight,
17421
+ settings.EColumnPaddingRight,
17422
+ ],
17423
+ );
17424
+
17425
+ const columnPaddingBottomByKey = useMemo(
17426
+ () => getNumericSettingValues(settings, COLUMN_PADDING_BOTTOM_KEYS),
17427
+ [
17428
+ settings.AColumnPaddingBottom,
17429
+ settings.BColumnPaddingBottom,
17430
+ settings.CColumnPaddingBottom,
17431
+ settings.DColumnPaddingBottom,
17432
+ settings.EColumnPaddingBottom,
17433
+ ],
17434
+ );
17435
+
17436
+ const columnContentOrder = useMemo((): typeof COLUMN_CONTENT_KEYS[number][] => {
17437
+ if (Array.isArray(columnsOrder) && columnsOrder.length > 0) {
17438
+ return columnsOrder as typeof COLUMN_CONTENT_KEYS[number][];
17439
+ }
17440
+ return [...COLUMN_CONTENT_KEYS];
17441
+ }, [columnsOrder]);
17442
+
17443
+ const listColumns = useMemo(
17444
+ () => buildListColumns(
17445
+ columnContentOrder,
17446
+ columns,
17447
+ columnWidthByKey,
17448
+ columnPaddingLeftByKey,
17449
+ columnPaddingRightByKey,
17450
+ columnPaddingBottomByKey,
17451
+ ),
17452
+ [columnContentOrder, columns, columnWidthByKey, columnPaddingLeftByKey, columnPaddingRightByKey, columnPaddingBottomByKey],
17453
+ );
17454
+
17455
+ const resolvedContentWidth = getListEffectiveContentWidth(settings);
17456
+
17457
+ const storedColumnWidths = useMemo(
17458
+ () => COLUMN_WIDTH_KEYS.slice(0, columns).map((key) => columnWidthByKey[key]),
17459
+ [columns, columnWidthByKey],
17460
+ );
17461
+
17462
+ const resolvedColumnWidths = useMemo(
17463
+ () => resolveListColumnWidths(columns, resolvedContentWidth, columnWidthByKey),
17464
+ [columns, resolvedContentWidth, columnWidthByKey],
17465
+ );
17466
+
17467
+ const effectiveColumnWidths = useMemo(
17468
+ () => getEffectiveListColumnWidths(columns, resolvedContentWidth, columnWidthByKey),
17469
+ [columns, resolvedContentWidth, columnWidthByKey],
17470
+ );
17471
+
17472
+ const effectiveColumnPaddings = useMemo(
17473
+ () =>
17474
+ listColumns.map((col, index) =>
17475
+ resolveListColumnPadding(
17476
+ effectiveColumnWidths[index] ?? 0,
17477
+ col.paddingLeft,
17478
+ col.paddingRight,
17479
+ )),
17480
+ [listColumns, effectiveColumnWidths],
17481
+ );
17482
+
17483
+ const allRows: ListItemRow[] = useMemo(() => {
17484
+ const resEntriesCount = entriesCount === 0 ? Infinity : entriesCount;
17485
+ const items = (content ?? []).slice(0, resEntriesCount);
17486
+
17487
+ return items.map((item, index) => ({
17488
+ id: index,
17489
+ cells: Object.fromEntries(
17490
+ COLUMN_CONTENT_KEYS.map((key) => [key, item[key] ?? ''])
17491
+ ),
17492
+ image: item.image,
17493
+ link: item.link,
17494
+ }));
17495
+ }, [content, entriesCount]);
17496
+
17497
+ const effectiveVisibleCount = cutEnabled
17498
+ ? (visibleRowCount ?? cut)
17499
+ : allRows.length;
17500
+
17501
+ const visibleRows = useMemo(() => {
17502
+ if (cutEnabled) {
17503
+ return allRows.slice(0, effectiveVisibleCount);
17504
+ }
17505
+ return allRows;
17506
+ }, [allRows, cutEnabled, effectiveVisibleCount]);
17507
+
17508
+ const showCutLabel = cutEnabled && effectiveVisibleCount < allRows.length;
17509
+
17510
+ const hasBetweenItemDividers = visibleRows.length > 1 || showCutLabel;
17511
+ const dividerClassNames = [
17512
+ showDividerTop ? \`\${P}-divider-top\` : '',
17513
+ showDividerBottom || hasBetweenItemDividers ? \`\${P}-divider-bottom\` : '',
17514
+ ].filter(Boolean).join(' ');
17515
+
17516
+ const handleShowMore = () => {
17517
+ const currentVisible = visibleRowCount ?? cut;
17518
+ if (!showCut) {
17519
+ setVisibleRowCount(allRows.length);
17520
+ return;
17521
+ }
17522
+ setVisibleRowCount(Math.min(currentVisible + showCut, allRows.length));
17523
+ };
17524
+
17525
+ const scaled = (v: number) => scalingValue(v, isEditor ?? false);
17526
+ const resolvedRowPaddingTop = isVerticalLayout
17527
+ ? (rowPaddingTopB ?? 0)
17528
+ : (rowPaddingTop ?? 0);
17529
+ const resolvedRowPaddingBottom = rowPaddingBottom ?? 0;
17530
+ const resolvedCellMinHeight = cellMinHeight ?? 0;
17531
+ const rowPaddingTopControlKey = isVerticalLayout ? 'rowPaddingTopB' : 'rowPaddingTop';
17532
+ const firstColumn = listColumns[0];
17533
+ const lastColumn = listColumns[listColumns.length - 1];
17534
+ const firstColumnEffectivePadding = effectiveColumnPaddings[0];
17535
+ const lastColumnEffectivePadding = effectiveColumnPaddings[effectiveColumnPaddings.length - 1];
17536
+ const firstColumnPaddingLeftWidth = firstColumn && firstColumnEffectivePadding
17537
+ ? Math.max(firstColumnEffectivePadding.paddingLeft, COL_PADDING_HANDLE_WIDTH)
17538
+ : 0;
17539
+ const lastColumnPaddingRightWidth = lastColumn && lastColumnEffectivePadding
17540
+ ? Math.max(lastColumnEffectivePadding.paddingRight, COL_PADDING_HANDLE_WIDTH)
17541
+ : 0;
17542
+ const columnsRightEdge = resolvedContentWidth;
17543
+
17544
+ const getHoverImagePosition = (event: React.MouseEvent) => {
17545
+ const container = containerRef.current;
17546
+ if (!container) {
17547
+ return { x: 0, y: 0 };
17548
+ }
17549
+
17550
+ const rect = container.getBoundingClientRect();
17551
+ return {
17552
+ x: event.clientX - rect.left + HOVER_IMAGE_CURSOR_OFFSET,
17553
+ y: event.clientY - rect.top + HOVER_IMAGE_CURSOR_OFFSET,
17554
+ };
17555
+ };
17556
+
17557
+ const handleRowMouseEnter = (row: ListItemRow, event: React.MouseEvent) => {
17558
+ if (!showHoverImage) return;
17559
+
17560
+ const image = row.image;
17561
+ if (!image?.url) {
17562
+ setHoverImage(null);
17563
+ return;
17564
+ }
17565
+
17566
+ const { x, y } = getHoverImagePosition(event);
17567
+ const minWidth = imageSize?.min ?? 80;
17568
+ const maxWidth = imageSize?.max ?? 320;
17569
+ const widthPx = hoverImage?.rowId === row.id
17570
+ ? hoverImage.widthPx
17571
+ : randomBetween(minWidth, maxWidth);
17572
+
17573
+ setHoverImage({
17574
+ rowId: row.id,
17575
+ url: image.url,
17576
+ objectFit: image.objectFit ?? 'cover',
17577
+ widthPx,
17578
+ x,
17579
+ y,
17580
+ });
17581
+ };
17582
+
17583
+ const handleWrapperMouseMove = (event: React.MouseEvent) => {
17584
+ if (!showHoverImage || !hoverImage) return;
17585
+
17586
+ const { x, y } = getHoverImagePosition(event);
17587
+ setHoverImage((prev) => {
17588
+ if (!prev) return prev;
17589
+ if (prev.x === x && prev.y === y) return prev;
17590
+ return { ...prev, x, y };
17591
+ });
17592
+ };
17593
+
17594
+ const handleWrapperMouseLeave = () => {
17595
+ setHoverImage(null);
17596
+ };
17597
+
17598
+ const hasBaselineColumn = useMemo(
17599
+ () =>
17600
+ !isVerticalLayout &&
17601
+ COLUMN_TEXT_PREFIXES.some((prefix) => {
17602
+ const columnLetter = prefix.charAt(0);
17603
+ const valign = settings[\`\${prefix}VerticalAlign\` as ListColumnVerticalAlignKey];
17604
+ return isActiveBaselineVAlign(valign, settings, columnLetter);
17605
+ }),
17606
+ [
17607
+ isVerticalLayout,
17608
+ settings,
17609
+ settings.AColumnVerticalAlign,
17610
+ settings.BColumnVerticalAlign,
17611
+ settings.CColumnVerticalAlign,
17612
+ settings.DColumnVerticalAlign,
17613
+ settings.EColumnVerticalAlign,
17614
+ ],
17615
+ );
17616
+
17617
+ useLayoutEffect(() => {
17618
+ const container = containerRef.current;
17619
+ if (!container) return;
17620
+
17621
+ const clearBaselineStyles = () => {
17622
+ container.querySelectorAll<HTMLElement>('[data-list-col]').forEach((el) => {
17623
+ el.style.transform = '';
17624
+ const listCol = el.querySelector<HTMLElement>(\`.\${P}-list-col\`);
17625
+ if (listCol) {
17626
+ listCol.style.minHeight = '';
17627
+ listCol.style.height = '';
17628
+ }
17629
+ const title = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);
17630
+ if (title) {
17631
+ title.style.transform = '';
17632
+ }
17633
+ });
17634
+ };
17635
+
17636
+ if (isVerticalLayout || !hasBaselineColumn) {
17637
+ clearBaselineStyles();
17638
+ return;
17639
+ }
17640
+
17641
+ const applyBaselines = () => {
17642
+ container.querySelectorAll<HTMLElement>('[data-list-row]').forEach((rowEl) => {
17643
+ const cols = Array.from(rowEl.querySelectorAll<HTMLElement>('[data-list-col]'));
17644
+ cols.forEach((el) => {
17645
+ el.style.transform = '';
17646
+ const listCol = el.querySelector<HTMLElement>(\`.\${P}-list-col\`);
17647
+ if (listCol) {
17648
+ listCol.style.minHeight = '';
17649
+ listCol.style.height = '';
17650
+ }
17651
+ const title = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);
17652
+ if (title) {
17653
+ title.style.transform = '';
17654
+ }
17655
+ });
17656
+
17657
+ syncRowListColHeights(rowEl, cols, \`\${P}-list-col\`);
17658
+ void rowEl.offsetHeight;
17659
+ const rowTop = rowEl.getBoundingClientRect().top;
17660
+
17661
+ type ColInfo = {
17662
+ el: HTMLElement;
17663
+ titleEl: HTMLElement | null;
17664
+ letter: string;
17665
+ kind: string;
17666
+ anchor: string | null;
17667
+ };
17668
+
17669
+ const probeClassName = \`\${P}-baseline-probe\`;
17670
+ const byLetter = new Map<string, ColInfo>();
17671
+ const infos: ColInfo[] = cols.map((el) => {
17672
+ const titleEl = el.querySelector<HTMLElement>(\`.\${P}-list-col-title\`);
17673
+ const info: ColInfo = {
17674
+ el,
17675
+ titleEl,
17676
+ letter: el.getAttribute('data-col-letter') ?? '',
17677
+ kind: el.getAttribute('data-valign') ?? 'top',
17678
+ anchor: el.getAttribute('data-valign-anchor'),
17679
+ };
17680
+ byLetter.set(info.letter, info);
17681
+ return info;
17682
+ });
17683
+
17684
+ const finalBaseline = new Map<string, number>();
17685
+ const resolve = (info: ColInfo, stack: Set<string>): number => {
17686
+ const cached = finalBaseline.get(info.letter);
17687
+ if (cached !== undefined) return cached;
17688
+
17689
+ const anchor = info.anchor ? byLetter.get(info.anchor) : undefined;
17690
+ if (info.kind !== 'baseline' || !anchor || stack.has(info.letter)) {
17691
+ const baseline = measureColumnFirstLineBaselineOffset(
17692
+ info,
17693
+ rowTop,
17694
+ \`\${P}-list-col\`,
17695
+ probeClassName,
17696
+ );
17697
+ finalBaseline.set(info.letter, baseline);
17698
+ return baseline;
17699
+ }
17700
+
17701
+ stack.add(info.letter);
17702
+ const anchorBaseline = resolve(anchor, stack);
17703
+ stack.delete(info.letter);
17704
+
17705
+ const followerNatural = measureColumnFirstLineBaselineOffset(
17706
+ info,
17707
+ rowTop,
17708
+ \`\${P}-list-col\`,
17709
+ probeClassName,
17710
+ );
17711
+ const shift = anchorBaseline - followerNatural;
17712
+ applyBaselineTitleShift(info.titleEl, shift);
17713
+
17714
+ const result = measureColumnFirstLineBaselineOffset(
17715
+ info,
17716
+ rowTop,
17717
+ \`\${P}-list-col\`,
17718
+ probeClassName,
17719
+ );
17720
+ finalBaseline.set(info.letter, result);
17721
+ return result;
17722
+ };
17723
+
17724
+ infos.forEach((info) => resolve(info, new Set<string>()));
17725
+ });
17726
+ };
17727
+
17728
+ applyBaselines();
17729
+
17730
+ const observer = new ResizeObserver(() => applyBaselines());
17731
+ observer.observe(container);
17732
+
17733
+ let cancelled = false;
17734
+ if (typeof document !== 'undefined' && document.fonts?.ready) {
17735
+ document.fonts.ready.then(() => {
17736
+ if (!cancelled) applyBaselines();
17737
+ });
17738
+ }
17739
+
17740
+ return () => {
17741
+ cancelled = true;
17742
+ observer.disconnect();
17743
+ clearBaselineStyles();
17744
+ };
17745
+ }, [
17746
+ hasBaselineColumn,
17747
+ isVerticalLayout,
17748
+ settings,
17749
+ content,
17750
+ designWidth,
17751
+ visibleRows,
17752
+ effectiveColumnWidths,
17753
+ ]);
17754
+
17755
+ return (
17756
+ <>
17757
+ <style dangerouslySetInnerHTML={{ __html: getCSS(P) }} />
17758
+ <div style={colorVars}>
17759
+ <div
17760
+ ref={containerRef}
17761
+ className={\`\${P}-wrapper \${wrapperStateClasses}\${dividerClassNames ? \` \${dividerClassNames}\` : ''}\${isVerticalLayout ? \` \${P}-type-b\` : ''}\`.trim()}
17762
+ style={{
17763
+ width: scalingValue(wrapperWidth ?? 0, isEditor),
17764
+ }}
17765
+ onMouseMove={showHoverImage ? handleWrapperMouseMove : undefined}
17766
+ onMouseLeave={showHoverImage ? handleWrapperMouseLeave : undefined}
17767
+ >
17768
+ <div style={{ width: '100%' }}>
17769
+ {visibleRows.map((row, rowIdx) => {
17770
+ const hasLink = (row.link?.length ?? 0) > 0;
17771
+ const RowElement = hasLink ? 'a' : 'div';
17772
+ const rowStyle = getEntryDividerWidths(
17773
+ rowIdx,
17774
+ visibleRows.length,
17775
+ showDividerTop,
17776
+ showDividerBottom,
17777
+ showCutLabel,
17778
+ dividerWidth ?? 0,
17779
+ isEditor ?? false,
17780
+ );
17781
+
17782
+ return (
17783
+ <RowElement
17784
+ key={row.id}
17785
+ className={\`\${P}-list-item\${hasLink ? \` \${P}-list-item-has-link\` : ''}\`}
17786
+ {...(hasLink ? { href: row.link, target: '_blank' } : {})}
17787
+ style={rowStyle}
17788
+ onMouseEnter={showHoverImage ? (event) => handleRowMouseEnter(row, event) : undefined}
17789
+ >
17790
+ {(resolvedRowPaddingTop > 0 || showControls) && (
17791
+ <div
17792
+ {...(showControls ? {
17793
+ 'data-controls': rowPaddingTopControlKey,
17794
+ 'data-controls-axis': 'y',
17795
+ 'data-controls-min': '0',
17796
+ } : {})}
17797
+ className={\`\${P}-row-padding-handle\`}
17798
+ style={{ height: scaled(resolvedRowPaddingTop) }}
17799
+ />
17800
+ )}
17801
+ <div
17802
+ className={\`\${P}-list-cols-row\${isVerticalLayout ? '' : \` \${P}-list-cols-row-h\`}\`}
17803
+ {...(isVerticalLayout ? {} : { 'data-list-row': '' })}
17804
+ style={isVerticalLayout ? undefined : { minHeight: scaled(resolvedCellMinHeight) }}
17805
+ >
17806
+ {listColumns.map((col, colIndex) => {
17807
+ const isLastColumn = colIndex === listColumns.length - 1;
17808
+ const effectivePadding = effectiveColumnPaddings[colIndex];
17809
+ const columnPaddingBottom = col.paddingBottom;
17810
+ const hasColumnText = hasListColumnText(row.cells[col.key]);
17811
+ const showColumnPaddingBottom = isVerticalLayout
17812
+ && hasColumnText
17813
+ && (columnPaddingBottom > 0 || showControls);
17814
+ const columnSizeStyle = isVerticalLayout
17815
+ ? { minHeight: scaled(resolvedCellMinHeight) }
17816
+ : (isLastColumn ? {} : { width: scaled(effectiveColumnWidths[colIndex]) });
17817
+ const columnPaddingStyle = isVerticalLayout
17818
+ ? {
17819
+ paddingLeft: scaled(effectiveTextPaddingLR),
17820
+ paddingRight: scaled(effectiveTextPaddingLR),
17821
+ }
17822
+ : {
17823
+ paddingLeft: scaled(effectivePadding.paddingLeft),
17824
+ paddingRight: scaled(effectivePadding.paddingRight),
17825
+ };
17826
+ const columnLetter = col.textPrefix.charAt(0);
17827
+ const vAlign = isVerticalLayout
17828
+ ? { kind: 'top' as const }
17829
+ : resolveColumnVerticalAlign(
17830
+ settings[\`\${col.textPrefix}VerticalAlign\` as ListColumnVerticalAlignKey],
17831
+ settings,
17832
+ columnLetter,
17833
+ );
17834
+
17835
+ return (
17836
+ <div
17837
+ key={col.key}
17838
+ {...(isVerticalLayout
17839
+ ? {}
17840
+ : {
17841
+ 'data-list-col': '',
17842
+ 'data-col-letter': columnLetter,
17843
+ 'data-valign': vAlign.kind,
17844
+ ...(vAlign.kind === 'baseline'
17845
+ ? { 'data-valign-anchor': vAlign.anchorLetter }
17846
+ : {}),
17847
+ })}
17848
+ >
17849
+ <div
17850
+ className={\`\${P}-list-col\${isLastColumn ? \` \${P}-list-col-last\` : ''}\`}
17851
+ style={{
17852
+ ...columnPaddingStyle,
17853
+ ...columnSizeStyle,
17854
+ }}
17855
+ data-test={col.width}
17856
+ >
17857
+ <span
17858
+ className={getListColumnTitleClassName(
17859
+ settings,
17860
+ col.textPrefix,
17861
+ \`\${P}-list-col-title\`,
17862
+ \`\${P}-text-tight-leading\`,
17863
+ )}
17864
+ style={{
17865
+ ...listColumnTextFieldsToCss(resolveListColumnTextFields(settings, col.textPrefix), isEditor),
17866
+ ...getListColumnTitleVars(settings, col.textPrefix, P, isEditor),
17867
+ ...(!isVerticalLayout ? vAlignToTitleStyle(vAlign.kind) : {}),
17868
+ }}
17869
+ >
17870
+ {row.cells[col.key] ?? null}
17871
+ </span>
17872
+ </div>
17873
+ {showColumnPaddingBottom && (
17874
+ <div
17875
+ {...(showControls ? {
17876
+ 'data-controls': col.paddingBottomKey,
17877
+ 'data-controls-axis': 'y',
17878
+ 'data-controls-min': '0',
17879
+ } : {})}
17880
+ className={\`\${P}-row-padding-handle\`}
17881
+ style={{ height: scaled(columnPaddingBottom) }}
17882
+ />
17883
+ )}
17884
+ </div>
17885
+ );
17886
+ })}
17887
+ </div>
17888
+ {!isVerticalLayout && (resolvedRowPaddingBottom > 0 || showControls) && (
17889
+ <div
17890
+ {...(showControls ? {
17891
+ 'data-controls': 'rowPaddingBottom',
17892
+ 'data-controls-axis': 'y',
17893
+ 'data-controls-min': '0',
17894
+ } : {})}
17895
+ className={\`\${P}-row-padding-handle\`}
17896
+ style={{ height: scaled(resolvedRowPaddingBottom) }}
17897
+ />
17898
+ )}
17899
+ </RowElement>
17900
+ );
17901
+ })}
17902
+ {showCutLabel && (
17903
+ <button
17904
+ type="button"
17905
+ className={\`\${P}-cut-item\`}
17906
+ style={{
17907
+ minHeight: scaled(cutCellMinHeight ?? 0),
17908
+ ...getCutItemDividerWidths(
17909
+ showDividerBottom,
17910
+ dividerWidth ?? 0,
17911
+ isEditor ?? false,
17912
+ ),
17913
+ }}
17914
+ onClick={handleShowMore}
17915
+ >
17916
+ <div
17917
+ className={\`\${P}-list-cols-row\`}
17918
+ style={
17919
+ isVerticalLayout
17920
+ ? {
17921
+ paddingLeft: scaled(effectiveTextPaddingLR),
17922
+ paddingRight: scaled(effectiveTextPaddingLR),
17923
+ }
17924
+ : { justifyContent: 'center' }
17925
+ }
17926
+ >
17927
+ <span
17928
+ className={getListColumnTitleClassName(
17929
+ settings,
17930
+ CUT_LABEL_TEXT_PREFIX,
17931
+ \`\${P}-cut-label\`,
17932
+ \`\${P}-text-tight-leading\`,
17933
+ )}
17934
+ style={{
17935
+ ...listColumnTextFieldsToCss(resolveListColumnTextFields(settings, CUT_LABEL_TEXT_PREFIX), isEditor),
17936
+ ...getListColumnTitleVars(settings, CUT_LABEL_TEXT_PREFIX, P, isEditor),
17937
+ }}
17938
+ >
17939
+ {cutLabel}
17940
+ </span>
17941
+ </div>
17942
+ </button>
17943
+ )}
17944
+ </div>
17945
+ {showControls && !isVerticalLayout && firstColumn && lastColumn && (
17946
+ <div key="column-edge-padding-handles" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
17947
+ <div
17948
+ data-controls={firstColumn.paddingLeftKey}
17949
+ data-controls-axis="x"
17950
+ data-controls-variant="column-padding"
17951
+ data-controls-min="0"
17952
+ data-controls-max-fraction={String(
17953
+ effectiveColumnWidths[0] - (firstColumnEffectivePadding?.paddingRight ?? 0),
17954
+ )}
17955
+ data-controls-static-handle=""
17956
+ className={\`\${P}-padding-control-handle\`}
17957
+ style={{
17958
+ position: 'absolute',
17959
+ top: 0,
17960
+ left: 0,
17961
+ width: scaled(firstColumnPaddingLeftWidth),
17962
+ height: '100%',
17963
+ pointerEvents: 'auto',
17964
+ zIndex: 2,
17965
+ }}
17966
+ />
17967
+ <div
17968
+ data-controls={lastColumn.paddingRightKey}
17969
+ data-controls-axis="x"
17970
+ data-controls-variant="column-padding"
17971
+ data-controls-reverse=""
17972
+ data-controls-min="0"
17973
+ data-controls-max-fraction={String(
17974
+ effectiveColumnWidths[listColumns.length - 1]
17975
+ - (lastColumnEffectivePadding?.paddingLeft ?? 0),
17976
+ )}
17977
+ data-controls-static-handle=""
17978
+ className={\`\${P}-padding-control-handle\`}
17979
+ style={{
17980
+ position: 'absolute',
17981
+ top: 0,
17982
+ left: scaled(columnsRightEdge - lastColumnPaddingRightWidth),
17983
+ width: scaled(lastColumnPaddingRightWidth),
17984
+ height: '100%',
17985
+ pointerEvents: 'auto',
17986
+ zIndex: 2,
17987
+ }}
17988
+ />
17989
+ </div>
17990
+ )}
17991
+ {showControls && !isVerticalLayout && listColumns.slice(0, -1).map((col, colIndex) => {
17992
+ const nextCol = listColumns[colIndex + 1];
17993
+ const maxColumnWidth = getColumnMaxWidth(
17994
+ colIndex,
17995
+ resolvedColumnWidths,
17996
+ storedColumnWidths,
17997
+ resolvedContentWidth,
17998
+ );
17999
+ const boundaryOffset = resolvedColumnWidths.slice(0, colIndex + 1).reduce((sum, width) => sum + width, 0);
18000
+ const colEffectivePadding = effectiveColumnPaddings[colIndex];
18001
+ const nextColEffectivePadding = effectiveColumnPaddings[colIndex + 1];
18002
+ const paddingRightWidth = Math.max(
18003
+ colEffectivePadding.paddingRight,
18004
+ COL_PADDING_HANDLE_WIDTH,
18005
+ );
18006
+ const paddingLeftWidth = Math.max(
18007
+ nextColEffectivePadding.paddingLeft,
18008
+ COL_PADDING_HANDLE_WIDTH,
18009
+ );
18010
+ const columnWidthHandleOffset = boundaryOffset - COL_RESIZE_HANDLE_WIDTH / 2;
18011
+
18012
+ return (
18013
+ <div key={\`\${col.widthKey}-junction\`} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
18014
+ <div
18015
+ data-controls={col.paddingRightKey}
18016
+ data-controls-axis="x"
18017
+ data-controls-variant="column-padding"
18018
+ data-controls-reverse=""
18019
+ data-controls-min="0"
18020
+ data-controls-max-fraction={String(
18021
+ effectiveColumnWidths[colIndex] - colEffectivePadding.paddingLeft,
18022
+ )}
18023
+ data-controls-static-handle=""
18024
+ className={\`\${P}-padding-control-handle\`}
18025
+ style={{
18026
+ position: 'absolute',
18027
+ top: 0,
18028
+ left: scaled(boundaryOffset - paddingRightWidth),
18029
+ width: scaled(paddingRightWidth),
18030
+ height: '100%',
18031
+ pointerEvents: 'auto',
18032
+ zIndex: 2,
18033
+ }}
18034
+ />
18035
+ <div
18036
+ data-controls={col.widthKey}
18037
+ data-controls-axis="x"
18038
+ data-controls-min={String(MIN_COLUMN_WIDTH_PX)}
18039
+ data-controls-max-fraction={String(maxColumnWidth)}
18040
+ data-controls-variant="column-width"
18041
+ className={\`\${P}-col-resize-handle\`}
18042
+ style={{
18043
+ position: 'absolute',
18044
+ top: '0px',
18045
+ left: scaled(columnWidthHandleOffset),
18046
+ width: scaled(COL_RESIZE_HANDLE_WIDTH),
18047
+ height: 'calc(100%)',
18048
+ pointerEvents: 'auto',
18049
+ zIndex: 4,
18050
+ }}
18051
+ />
18052
+ <div
18053
+ data-controls={nextCol.paddingLeftKey}
18054
+ data-controls-axis="x"
18055
+ data-controls-variant="column-padding"
18056
+ data-controls-min="0"
18057
+ data-controls-max-fraction={String(
18058
+ effectiveColumnWidths[colIndex + 1] - nextColEffectivePadding.paddingRight,
18059
+ )}
18060
+ data-controls-static-handle=""
18061
+ className={\`\${P}-padding-control-handle\`}
18062
+ style={{
18063
+ position: 'absolute',
18064
+ top: 0,
18065
+ left: scaled(boundaryOffset),
18066
+ width: scaled(paddingLeftWidth),
18067
+ height: '100%',
18068
+ pointerEvents: 'auto',
18069
+ zIndex: 2,
18070
+ }}
18071
+ />
18072
+ </div>
18073
+ );
18074
+ })}
18075
+ {showControls && isVerticalLayout && (
18076
+ <div key="text-padding-lr-handles" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
18077
+ <div
18078
+ data-controls="textPaddingLR"
18079
+ data-controls-paired=""
18080
+ data-controls-axis="x"
18081
+ data-controls-min="0"
18082
+ data-controls-max-fraction={String(textPaddingLRMaxFraction)}
18083
+ data-controls-static-handle=""
18084
+ className={\`\${P}-text-padding-lr-handle\`}
18085
+ style={{
18086
+ position: 'absolute',
18087
+ top: 0,
18088
+ left: 0,
18089
+ width: scaled(textPaddingLRHandleWidth),
18090
+ height: '100%',
18091
+ pointerEvents: 'auto',
18092
+ zIndex: 2,
18093
+ }}
18094
+ />
18095
+ <div
18096
+ data-controls="textPaddingLR"
18097
+ data-controls-paired=""
18098
+ data-controls-axis="x"
18099
+ data-controls-reverse=""
18100
+ data-controls-min="0"
18101
+ data-controls-max-fraction={String(textPaddingLRMaxFraction)}
18102
+ data-controls-static-handle=""
18103
+ className={\`\${P}-text-padding-lr-handle\`}
18104
+ style={{
18105
+ position: 'absolute',
18106
+ top: 0,
18107
+ left: scaled(Math.max(textPaddingLRHandleWidth, resolvedContentWidth - textPaddingLRHandleWidth)),
18108
+ width: scaled(textPaddingLRHandleWidth),
18109
+ height: '100%',
18110
+ pointerEvents: 'auto',
18111
+ zIndex: 2,
18112
+ }}
18113
+ />
18114
+ </div>
18115
+ )}
18116
+ {showHoverImage && hoverImage && (
18117
+ <img
18118
+ className={\`\${P}-hover-image\`}
18119
+ src={hoverImage.url}
18120
+ alt=""
18121
+ style={{
18122
+ width: sv(hoverImage.widthPx),
18123
+ objectFit: hoverImage.objectFit,
18124
+ left: hoverImage.x,
18125
+ top: hoverImage.y,
18126
+ }}
18127
+ />
18128
+ )}
18129
+ </div>
18130
+ </div>
18131
+ </>
18132
+ );
18133
+ }
18134
18134
  `, Gt = ["A", "B", "C", "D", "E"], ei = [
18135
18135
  ...sd,
18136
18136
  "Baseline A",