kempo-ui 0.4.11 → 0.4.13

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 (104) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/components/SegmentedControl.js +16 -0
  3. package/dist/components/Tabs.js +4 -4
  4. package/docs/components/SegmentedControl.html +649 -0
  5. package/docs/components/accordion.html +3 -0
  6. package/docs/components/aside.html +3 -0
  7. package/docs/components/calendar.html +3 -0
  8. package/docs/components/card.html +3 -0
  9. package/docs/components/chat.html +3 -0
  10. package/docs/components/code-editor.html +3 -0
  11. package/docs/components/color-picker.html +3 -0
  12. package/docs/components/combobox.html +3 -0
  13. package/docs/components/content-slider.html +3 -0
  14. package/docs/components/context.html +3 -0
  15. package/docs/components/dialog.html +3 -0
  16. package/docs/components/dropdown.html +3 -0
  17. package/docs/components/filter-list.html +3 -0
  18. package/docs/components/focus-capture.html +3 -0
  19. package/docs/components/html-editor.html +3 -0
  20. package/docs/components/hybrid-component.html +3 -0
  21. package/docs/components/icon.html +3 -0
  22. package/docs/components/import.html +3 -0
  23. package/docs/components/light-component.html +3 -0
  24. package/docs/components/markdown-editor.html +3 -0
  25. package/docs/components/markdown.html +3 -0
  26. package/docs/components/nav-spacer.html +3 -0
  27. package/docs/components/nav.html +3 -0
  28. package/docs/components/photo-viewer.html +3 -0
  29. package/docs/components/progress.html +3 -0
  30. package/docs/components/resize.html +3 -0
  31. package/docs/components/segmented-control.html +728 -0
  32. package/docs/components/shadow-component.html +3 -0
  33. package/docs/components/show-more.html +3 -0
  34. package/docs/components/slider.html +3 -0
  35. package/docs/components/sortable.html +3 -0
  36. package/docs/components/speech-to-text.html +3 -0
  37. package/docs/components/spinner.html +3 -0
  38. package/docs/components/split.html +3 -0
  39. package/docs/components/table.html +3 -0
  40. package/docs/components/tableControls.html +3 -0
  41. package/docs/components/tableCustomFields.html +3 -0
  42. package/docs/components/tableFetchRecords.html +3 -0
  43. package/docs/components/tableFieldSortHide.html +3 -0
  44. package/docs/components/tablePagination.html +3 -0
  45. package/docs/components/tablePlaceholder.html +3 -0
  46. package/docs/components/tableRecordEditing.html +3 -0
  47. package/docs/components/tableRecordFiltering.html +3 -0
  48. package/docs/components/tableRecordHiding.html +3 -0
  49. package/docs/components/tableRecordSearching.html +3 -0
  50. package/docs/components/tableRecordSelection.html +3 -0
  51. package/docs/components/tableRowControls.html +3 -0
  52. package/docs/components/tableServerSync.html +3 -0
  53. package/docs/components/tableSorting.html +3 -0
  54. package/docs/components/tabs.html +32 -0
  55. package/docs/components/tags.html +3 -0
  56. package/docs/components/text-to-speech.html +3 -0
  57. package/docs/components/theme-select.html +3 -0
  58. package/docs/components/theme-switcher.html +3 -0
  59. package/docs/components/time.html +3 -0
  60. package/docs/components/timestamp.html +3 -0
  61. package/docs/components/toast.html +3 -0
  62. package/docs/components/toggle.html +3 -0
  63. package/docs/components/tree.html +3 -0
  64. package/docs/components/voice-selector.html +3 -0
  65. package/docs/icons/account-circle.svg +1 -1
  66. package/docs/index.html +9 -0
  67. package/docs/src/components/SegmentedControl.js +16 -0
  68. package/docs/src/components/Tabs.js +4 -4
  69. package/docs/utils/context.html +3 -0
  70. package/docs/utils/cookie.html +3 -0
  71. package/docs/utils/debounce.html +3 -0
  72. package/docs/utils/drag.html +3 -0
  73. package/docs/utils/elevation.html +3 -0
  74. package/docs/utils/formatTimestamp.html +3 -0
  75. package/docs/utils/object.html +3 -0
  76. package/docs/utils/propConverters.html +3 -0
  77. package/docs/utils/sanitizeHtml.html +3 -0
  78. package/docs/utils/string.html +3 -0
  79. package/docs/utils/theme.html +3 -0
  80. package/docs/utils/toTitleCase.html +3 -0
  81. package/docs/utils/type.html +3 -0
  82. package/docs/utils/voice.html +3 -0
  83. package/docs/utils/wait.html +3 -0
  84. package/docs-src/components/segmented-control.page.html +236 -0
  85. package/docs-src/components/tabs.page.html +29 -0
  86. package/docs-src/index.page.html +6 -0
  87. package/docs-src/nav.fragment.html +3 -0
  88. package/icons/account-circle.svg +1 -1
  89. package/llms.txt +2 -1
  90. package/package.json +1 -1
  91. package/src/components/SegmentedControl.js +118 -0
  92. package/src/components/Tabs.js +21 -1
  93. package/tasks/released/0004-create-segmented-control-component/component-rendering.png +0 -0
  94. package/tasks/released/0004-create-segmented-control-component/final-component-page.png +0 -0
  95. package/tasks/released/0004-create-segmented-control-component/form-integration-section.png +0 -0
  96. package/tasks/released/0004-create-segmented-control-component/option-element-section.png +0 -0
  97. package/tasks/released/0004-create-segmented-control-component/page-screenshot.png +0 -0
  98. package/tasks/released/0004-create-segmented-control-component/validation-form-integration.png +0 -0
  99. package/tasks/released/0004-create-segmented-control-component/validation-screenshot-1-full-page.png +0 -0
  100. package/tasks/released/0004-create-segmented-control-component/validation-screenshot-2-icon-options.png +0 -0
  101. package/tasks/released/0004-create-segmented-control-component.md +106 -0
  102. package/tasks/released/0005-add-persistent-id-to-tabs.md +98 -0
  103. package/tests/components/SegmentedControl.browser-test.js +223 -0
  104. package/tests/components/Tabs.browser-test.js +262 -0
@@ -843,5 +843,267 @@ export default {
843
843
 
844
844
  cleanup(container);
845
845
  pass('TabSpacer has flex grow');
846
+ },
847
+
848
+ 'persistent-id: should save active tab to localStorage': async ({pass, fail}) => {
849
+ const id = 'test-tabs-save-' + Date.now();
850
+ const key = `tabs-persistent-id-${id}`;
851
+ window.localStorage.removeItem(key);
852
+
853
+ const container = document.createElement('div');
854
+ container.innerHTML = `
855
+ <k-tabs persistent-id="${id}">
856
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
857
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
858
+ <k-tab for="tab3" slot="tabs">Tab 3</k-tab>
859
+ <k-tab-content name="tab1">Content 1</k-tab-content>
860
+ <k-tab-content name="tab2">Content 2</k-tab-content>
861
+ <k-tab-content name="tab3">Content 3</k-tab-content>
862
+ </k-tabs>
863
+ `;
864
+ document.body.appendChild(container);
865
+
866
+ const tabs = container.querySelector('k-tabs');
867
+ await tabs.updateComplete;
868
+
869
+ tabs.active = 'tab2';
870
+ await tabs.updateComplete;
871
+
872
+ const stored = window.localStorage.getItem(key);
873
+ window.localStorage.removeItem(key);
874
+ cleanup(container);
875
+
876
+ if(stored !== 'tab2'){
877
+ fail(`Expected localStorage to contain "tab2", got "${stored}"`);
878
+ return;
879
+ }
880
+
881
+ pass('Active tab saved to localStorage');
882
+ },
883
+
884
+ 'persistent-id: should restore active tab from localStorage': async ({pass, fail}) => {
885
+ const id = 'test-tabs-restore-' + Date.now();
886
+ const key = `tabs-persistent-id-${id}`;
887
+ window.localStorage.setItem(key, 'tab3');
888
+
889
+ const container = document.createElement('div');
890
+ container.innerHTML = `
891
+ <k-tabs persistent-id="${id}">
892
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
893
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
894
+ <k-tab for="tab3" slot="tabs">Tab 3</k-tab>
895
+ <k-tab-content name="tab1">Content 1</k-tab-content>
896
+ <k-tab-content name="tab2">Content 2</k-tab-content>
897
+ <k-tab-content name="tab3">Content 3</k-tab-content>
898
+ </k-tabs>
899
+ `;
900
+ document.body.appendChild(container);
901
+
902
+ const tabs = container.querySelector('k-tabs');
903
+ await tabs.updateComplete;
904
+ await new Promise(r => setTimeout(r, 50));
905
+
906
+ const tab1 = tabs.querySelector('k-tab[for="tab1"]');
907
+ const tab2 = tabs.querySelector('k-tab[for="tab2"]');
908
+ const tab3 = tabs.querySelector('k-tab[for="tab3"]');
909
+ const content1 = tabs.querySelector('k-tab-content[name="tab1"]');
910
+ const content2 = tabs.querySelector('k-tab-content[name="tab2"]');
911
+ const content3 = tabs.querySelector('k-tab-content[name="tab3"]');
912
+
913
+ window.localStorage.removeItem(key);
914
+ cleanup(container);
915
+
916
+ if(tabs.active !== 'tab3'){
917
+ fail(`Expected active to be "tab3", got "${tabs.active}"`);
918
+ return;
919
+ }
920
+ if(!tab3.active || content3.active){
921
+ fail('tab3 should be active (restored from localStorage)');
922
+ return;
923
+ }
924
+ if(tab1.active || tab2.active || content1.active || content2.active){
925
+ fail('tab1 and tab2 should not be active');
926
+ return;
927
+ }
928
+
929
+ pass('Active tab restored from localStorage');
930
+ },
931
+
932
+ 'persistent-id: should fire restored event when state is restored': async ({pass, fail}) => {
933
+ const id = 'test-tabs-event-' + Date.now();
934
+ const key = `tabs-persistent-id-${id}`;
935
+ window.localStorage.setItem(key, 'tab2');
936
+
937
+ const container = document.createElement('div');
938
+ container.innerHTML = `
939
+ <k-tabs persistent-id="${id}">
940
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
941
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
942
+ <k-tab-content name="tab1">Content 1</k-tab-content>
943
+ <k-tab-content name="tab2">Content 2</k-tab-content>
944
+ </k-tabs>
945
+ `;
946
+ document.body.appendChild(container);
947
+
948
+ const tabs = container.querySelector('k-tabs');
949
+ let restoredFired = false;
950
+ let restoredDetail = null;
951
+
952
+ tabs.addEventListener('restored', (e) => {
953
+ restoredFired = true;
954
+ restoredDetail = e.detail;
955
+ });
956
+
957
+ await tabs.updateComplete;
958
+ await new Promise(r => setTimeout(r, 50));
959
+
960
+ window.localStorage.removeItem(key);
961
+ cleanup(container);
962
+
963
+ if(!restoredFired){
964
+ fail('restored event should be fired');
965
+ return;
966
+ }
967
+ if(!restoredDetail || restoredDetail.tab !== 'tab2'){
968
+ fail(`Expected restored event detail to contain tab: "tab2", got ${JSON.stringify(restoredDetail)}`);
969
+ return;
970
+ }
971
+
972
+ pass('restored event fired with correct detail');
973
+ },
974
+
975
+ 'persistent-id: should fire tab event when restored': async ({pass, fail}) => {
976
+ const id = 'test-tabs-tab-event-' + Date.now();
977
+ const key = `tabs-persistent-id-${id}`;
978
+ window.localStorage.setItem(key, 'tab2');
979
+
980
+ const container = document.createElement('div');
981
+ container.innerHTML = `
982
+ <k-tabs persistent-id="${id}">
983
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
984
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
985
+ <k-tab-content name="tab1">Content 1</k-tab-content>
986
+ <k-tab-content name="tab2">Content 2</k-tab-content>
987
+ </k-tabs>
988
+ `;
989
+ document.body.appendChild(container);
990
+
991
+ const tabs = container.querySelector('k-tabs');
992
+ let tabEventFired = false;
993
+ let tabDetail = null;
994
+
995
+ tabs.addEventListener('tab', (e) => {
996
+ tabEventFired = true;
997
+ tabDetail = e.detail;
998
+ });
999
+
1000
+ await tabs.updateComplete;
1001
+ await new Promise(r => setTimeout(r, 50));
1002
+
1003
+ window.localStorage.removeItem(key);
1004
+ cleanup(container);
1005
+
1006
+ if(!tabEventFired){
1007
+ fail('tab event should be fired on restoration');
1008
+ return;
1009
+ }
1010
+ if(!tabDetail || tabDetail.tab !== 'tab2'){
1011
+ fail(`Expected tab event detail to contain tab: "tab2", got ${JSON.stringify(tabDetail)}`);
1012
+ return;
1013
+ }
1014
+
1015
+ pass('tab event fired on restoration with correct detail');
1016
+ },
1017
+
1018
+ 'persistent-id: should handle missing localStorage gracefully': async ({pass, fail}) => {
1019
+ const container = document.createElement('div');
1020
+ container.innerHTML = `
1021
+ <k-tabs persistent-id="test">
1022
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
1023
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
1024
+ <k-tab-content name="tab1">Content 1</k-tab-content>
1025
+ <k-tab-content name="tab2">Content 2</k-tab-content>
1026
+ </k-tabs>
1027
+ `;
1028
+ document.body.appendChild(container);
1029
+
1030
+ const tabs = container.querySelector('k-tabs');
1031
+ const originalLocalStorage = window.localStorage;
1032
+
1033
+ try {
1034
+ Object.defineProperty(window, 'localStorage', {
1035
+ value: null,
1036
+ configurable: true
1037
+ });
1038
+
1039
+ tabs.active = 'tab2';
1040
+ await tabs.updateComplete;
1041
+
1042
+ window.Object.defineProperty(window, 'localStorage', {
1043
+ value: originalLocalStorage,
1044
+ configurable: true
1045
+ });
1046
+
1047
+ cleanup(container);
1048
+ pass('Handles missing localStorage gracefully');
1049
+ } catch(e){
1050
+ window.Object.defineProperty(window, 'localStorage', {
1051
+ value: originalLocalStorage,
1052
+ configurable: true
1053
+ });
1054
+ cleanup(container);
1055
+ fail(`Should not throw error when localStorage is unavailable: ${e.message}`);
1056
+ }
1057
+ },
1058
+
1059
+ 'persistent-id: should maintain separate states for different ids': async ({pass, fail}) => {
1060
+ const id1 = 'test-tabs-id1-' + Date.now();
1061
+ const id2 = 'test-tabs-id2-' + Date.now();
1062
+ const key1 = `tabs-persistent-id-${id1}`;
1063
+ const key2 = `tabs-persistent-id-${id2}`;
1064
+
1065
+ window.localStorage.setItem(key1, 'tab1');
1066
+ window.localStorage.setItem(key2, 'tab2');
1067
+
1068
+ const container = document.createElement('div');
1069
+ container.innerHTML = `
1070
+ <div>
1071
+ <k-tabs persistent-id="${id1}">
1072
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
1073
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
1074
+ <k-tab-content name="tab1">Content 1</k-tab-content>
1075
+ <k-tab-content name="tab2">Content 2</k-tab-content>
1076
+ </k-tabs>
1077
+ <k-tabs persistent-id="${id2}">
1078
+ <k-tab for="tab1" slot="tabs">Tab 1</k-tab>
1079
+ <k-tab for="tab2" slot="tabs">Tab 2</k-tab>
1080
+ <k-tab-content name="tab1">Content 1</k-tab-content>
1081
+ <k-tab-content name="tab2">Content 2</k-tab-content>
1082
+ </k-tabs>
1083
+ </div>
1084
+ `;
1085
+ document.body.appendChild(container);
1086
+
1087
+ const tabs1 = container.querySelectorAll('k-tabs')[0];
1088
+ const tabs2 = container.querySelectorAll('k-tabs')[1];
1089
+
1090
+ await tabs1.updateComplete;
1091
+ await tabs2.updateComplete;
1092
+ await new Promise(r => setTimeout(r, 50));
1093
+
1094
+ window.localStorage.removeItem(key1);
1095
+ window.localStorage.removeItem(key2);
1096
+ cleanup(container);
1097
+
1098
+ if(tabs1.active !== 'tab1'){
1099
+ fail(`tabs1 should have active "tab1", got "${tabs1.active}"`);
1100
+ return;
1101
+ }
1102
+ if(tabs2.active !== 'tab2'){
1103
+ fail(`tabs2 should have active "tab2", got "${tabs2.active}"`);
1104
+ return;
1105
+ }
1106
+
1107
+ pass('Separate persistent-id instances maintain separate states');
846
1108
  }
847
1109
  };