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.
- package/CHANGELOG.md +24 -0
- package/dist/components/SegmentedControl.js +16 -0
- package/dist/components/Tabs.js +4 -4
- package/docs/components/SegmentedControl.html +649 -0
- package/docs/components/accordion.html +3 -0
- package/docs/components/aside.html +3 -0
- package/docs/components/calendar.html +3 -0
- package/docs/components/card.html +3 -0
- package/docs/components/chat.html +3 -0
- package/docs/components/code-editor.html +3 -0
- package/docs/components/color-picker.html +3 -0
- package/docs/components/combobox.html +3 -0
- package/docs/components/content-slider.html +3 -0
- package/docs/components/context.html +3 -0
- package/docs/components/dialog.html +3 -0
- package/docs/components/dropdown.html +3 -0
- package/docs/components/filter-list.html +3 -0
- package/docs/components/focus-capture.html +3 -0
- package/docs/components/html-editor.html +3 -0
- package/docs/components/hybrid-component.html +3 -0
- package/docs/components/icon.html +3 -0
- package/docs/components/import.html +3 -0
- package/docs/components/light-component.html +3 -0
- package/docs/components/markdown-editor.html +3 -0
- package/docs/components/markdown.html +3 -0
- package/docs/components/nav-spacer.html +3 -0
- package/docs/components/nav.html +3 -0
- package/docs/components/photo-viewer.html +3 -0
- package/docs/components/progress.html +3 -0
- package/docs/components/resize.html +3 -0
- package/docs/components/segmented-control.html +728 -0
- package/docs/components/shadow-component.html +3 -0
- package/docs/components/show-more.html +3 -0
- package/docs/components/slider.html +3 -0
- package/docs/components/sortable.html +3 -0
- package/docs/components/speech-to-text.html +3 -0
- package/docs/components/spinner.html +3 -0
- package/docs/components/split.html +3 -0
- package/docs/components/table.html +3 -0
- package/docs/components/tableControls.html +3 -0
- package/docs/components/tableCustomFields.html +3 -0
- package/docs/components/tableFetchRecords.html +3 -0
- package/docs/components/tableFieldSortHide.html +3 -0
- package/docs/components/tablePagination.html +3 -0
- package/docs/components/tablePlaceholder.html +3 -0
- package/docs/components/tableRecordEditing.html +3 -0
- package/docs/components/tableRecordFiltering.html +3 -0
- package/docs/components/tableRecordHiding.html +3 -0
- package/docs/components/tableRecordSearching.html +3 -0
- package/docs/components/tableRecordSelection.html +3 -0
- package/docs/components/tableRowControls.html +3 -0
- package/docs/components/tableServerSync.html +3 -0
- package/docs/components/tableSorting.html +3 -0
- package/docs/components/tabs.html +32 -0
- package/docs/components/tags.html +3 -0
- package/docs/components/text-to-speech.html +3 -0
- package/docs/components/theme-select.html +3 -0
- package/docs/components/theme-switcher.html +3 -0
- package/docs/components/time.html +3 -0
- package/docs/components/timestamp.html +3 -0
- package/docs/components/toast.html +3 -0
- package/docs/components/toggle.html +3 -0
- package/docs/components/tree.html +3 -0
- package/docs/components/voice-selector.html +3 -0
- package/docs/icons/account-circle.svg +1 -1
- package/docs/index.html +9 -0
- package/docs/src/components/SegmentedControl.js +16 -0
- package/docs/src/components/Tabs.js +4 -4
- package/docs/utils/context.html +3 -0
- package/docs/utils/cookie.html +3 -0
- package/docs/utils/debounce.html +3 -0
- package/docs/utils/drag.html +3 -0
- package/docs/utils/elevation.html +3 -0
- package/docs/utils/formatTimestamp.html +3 -0
- package/docs/utils/object.html +3 -0
- package/docs/utils/propConverters.html +3 -0
- package/docs/utils/sanitizeHtml.html +3 -0
- package/docs/utils/string.html +3 -0
- package/docs/utils/theme.html +3 -0
- package/docs/utils/toTitleCase.html +3 -0
- package/docs/utils/type.html +3 -0
- package/docs/utils/voice.html +3 -0
- package/docs/utils/wait.html +3 -0
- package/docs-src/components/segmented-control.page.html +236 -0
- package/docs-src/components/tabs.page.html +29 -0
- package/docs-src/index.page.html +6 -0
- package/docs-src/nav.fragment.html +3 -0
- package/icons/account-circle.svg +1 -1
- package/llms.txt +2 -1
- package/package.json +1 -1
- package/src/components/SegmentedControl.js +118 -0
- package/src/components/Tabs.js +21 -1
- package/tasks/released/0004-create-segmented-control-component/component-rendering.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/final-component-page.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/form-integration-section.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/option-element-section.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/page-screenshot.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/validation-form-integration.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/validation-screenshot-1-full-page.png +0 -0
- package/tasks/released/0004-create-segmented-control-component/validation-screenshot-2-icon-options.png +0 -0
- package/tasks/released/0004-create-segmented-control-component.md +106 -0
- package/tasks/released/0005-add-persistent-id-to-tabs.md +98 -0
- package/tests/components/SegmentedControl.browser-test.js +223 -0
- package/tests/components/Tabs.browser-test.js +262 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
|
+
### Added
|
|
9
|
+
- **Tabs component**: `persistent-id` attribute for storing/restoring active tab state
|
|
10
|
+
- New `persistentId` property (String type, reflects to `persistent-id` attribute)
|
|
11
|
+
- Active tab state is automatically saved to localStorage when it changes
|
|
12
|
+
- Previously active tab is automatically restored on page load
|
|
13
|
+
- Fires `restored` event when state is restored from localStorage
|
|
14
|
+
- Fires `tab` event on both manual change and state restoration
|
|
15
|
+
- Supports multiple Tabs components with different `persistent-id` values for independent state management
|
|
16
|
+
- Safe fallback when localStorage is unavailable
|
|
17
|
+
- New unit test suite with 6 test cases covering all persistence scenarios
|
|
18
|
+
|
|
19
|
+
## [0.4.12] - 2026-05-03
|
|
20
|
+
### Added
|
|
21
|
+
- **SegmentedControl component**: New form-integrated segmented control component
|
|
22
|
+
- Renders child `<k-sc-option>` elements as a button group using Kempo-CSS utility classes
|
|
23
|
+
- Supports rich content in options including text and icon elements (via `<k-icon>`)
|
|
24
|
+
- Full form integration using ElementInternals API (`formAssociated`) for proper form submission and reset
|
|
25
|
+
- `name` attribute for form field identification
|
|
26
|
+
- `value` property reflects and controls the selected option
|
|
27
|
+
- Dispatches `change` events when selection changes
|
|
28
|
+
- Comprehensive unit test suite with 13 test cases covering element creation, properties, option recognition, selection, styling, and events
|
|
29
|
+
- Complete documentation with examples: Basic Usage, Selected By Default, JavaScript Usage, Icon Options, and Form Integration
|
|
30
|
+
- Test file: `tests/components/SegmentedControl.browser-test.js`
|
|
31
|
+
- Documentation: `docs-src/components/segmented-control.page.html`
|
|
8
32
|
|
|
9
33
|
## [0.4.11] - 2026-05-01
|
|
10
34
|
### Added
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import{html as t,css as e,unsafeHTML as s}from"../lit-all.min.js";import n from"./ShadowComponent.js";class i extends n{static formAssociated=!0;static properties={value:{type:String,reflect:!0},name:{type:String}};constructor(){if(super(),this.value="",this.name="",this.initialValue="","function"==typeof this.attachInternals)try{this.internals=this.attachInternals()}catch(t){}}connectedCallback(){super.connectedCallback(),this.initialValue=this.getAttribute("value")||"",this.addEventListener("slotchange",this.handleSlotChange,!0);const t=this.closest("form");t&&t.addEventListener("reset",this.handleReset,!0)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("slotchange",this.handleSlotChange,!0);const t=this.closest("form");t&&t.removeEventListener("reset",this.handleReset,!0)}updated(t){if(super.updated(t),t.has("value")){if(this.internals&&"function"==typeof this.internals.setFormValue)try{this.internals.setFormValue(this.value||null)}catch(t){}this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))}}handleSlotChange=()=>{this.requestUpdate()};handleReset=()=>{this.value=this.initialValue};handleButtonClick=t=>{this.value=t};getOptions=()=>Array.from(this.children).filter(t=>"K-SC-OPTION"===t.tagName);render(){const e=this.getOptions();return t`
|
|
2
|
+
<div class="btn-grp">
|
|
3
|
+
${e.map(e=>{const n=e.getAttribute("value")||"",i=n===this.value;return t`
|
|
4
|
+
<button
|
|
5
|
+
class="${i?"primary":""}"
|
|
6
|
+
@click=${()=>this.handleButtonClick(n)}
|
|
7
|
+
?aria-pressed=${i}
|
|
8
|
+
>${s(e.innerHTML)}</button>
|
|
9
|
+
`})}
|
|
10
|
+
</div>
|
|
11
|
+
<slot style="display:none;"></slot>
|
|
12
|
+
`}static styles=e`
|
|
13
|
+
:host {
|
|
14
|
+
display: block;
|
|
15
|
+
}
|
|
16
|
+
`}class a extends HTMLElement{connectedCallback(){this.hasAttribute("value")||this.setAttribute("value","")}}export default i;customElements.define("k-segmented-control",i),customElements.define("k-sc-option",a);
|
package/dist/components/Tabs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{html as t,css as e}from"../lit-all.min.js";import
|
|
1
|
+
import{html as t,css as e}from"../lit-all.min.js";import s from"./ShadowComponent.js";import{boolExists as o}from"../utils/propConverters.js";export class Tabs extends s{static properties={active:{type:String,reflect:!0},fixedHeight:{type:Boolean,reflect:!0,attribute:"fixed-height",converter:o},persistentId:{type:String,reflect:!0,attribute:"persistent-id"}};constructor(){super(),this.active="",this.fixedHeight=!1,this.persistentId=null}firstUpdated(){if(super.firstUpdated(),!this.active){const t=this.querySelector("k-tab-content");t&&(this.active=t.name)}this.setupScrollListeners(),this.updateScrollIndicators(),new ResizeObserver(()=>this.updateScrollIndicators()).observe(this.shadowRoot.getElementById("tabs"))}updated(t){if(super.updated(t),t.has("persistentId")&&this.persistentId&&window?.localStorage){const t=`tabs-persistent-id-${this.persistentId}`,e=window.localStorage.getItem(t);null!==e&&(this.active=e,this.dispatchEvent(new CustomEvent("restored",{detail:{tab:e},bubbles:!0})))}t.has("active")&&this.updateActiveElements()}setupScrollListeners(){const t=this.shadowRoot.getElementById("tabs"),e=this.shadowRoot.getElementById("scroll-left"),s=this.shadowRoot.getElementById("scroll-right");t.addEventListener("scroll",()=>this.updateScrollIndicators()),e.addEventListener("click",()=>{t.scrollBy({left:-200,behavior:"smooth"})}),s.addEventListener("click",()=>{t.scrollBy({left:200,behavior:"smooth"})})}updateScrollIndicators(){const t=this.shadowRoot.getElementById("tabs"),e=this.shadowRoot.getElementById("scroll-left"),s=this.shadowRoot.getElementById("scroll-right"),o=t.scrollLeft>0,i=t.scrollLeft<t.scrollWidth-t.clientWidth;e.classList.toggle("visible",o),s.classList.toggle("visible",i)}updateActiveElements(){const t=this.getActiveTab();t&&(t.active=!1);const e=this.getActiveContent();e&&(e.active=!1);const s=this.getTab(this.active);s&&(s.active=!0);const o=this.getContent(this.active);if(o&&(o.active=!0),this.dispatchEvent(new CustomEvent("tab",{detail:{tab:this.active},bubbles:!0})),this.persistentId&&window?.localStorage){const t=`tabs-persistent-id-${this.persistentId}`;window.localStorage.setItem(t,this.active)}}get contents(){return[...this.querySelectorAll(":scope > k-tab-content")]}get tabs(){return[...this.querySelectorAll(":scope > k-tab")]}getTab(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab[for="${t}"]`)),!e){let s=parseInt(t);s||(s=0),e=this.querySelectorAll("k-tab")[s]}return e}getActiveTab(){return this.querySelector(":scope > k-tab[active]")}getContent(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab-content[name="${t}"]`)),!e){let s=parseInt(t);s||(s=0),e=this.querySelectorAll("k-tab-content")[s]}return e}getActiveContent(){return this.querySelector(":scope > k-tab-content[active]")}static styles=e`
|
|
2
2
|
:host {
|
|
3
3
|
display: block;
|
|
4
4
|
width: 100%;
|
|
@@ -99,7 +99,7 @@ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponen
|
|
|
99
99
|
<slot></slot>
|
|
100
100
|
</div>
|
|
101
101
|
</div>
|
|
102
|
-
`}}export class Tab extends
|
|
102
|
+
`}}export class Tab extends s{static properties={active:{type:Boolean,reflect:!0,converter:o},for:{type:String,reflect:!0}};constructor(){super(),this.active=!1,this.for="",this.slot="tabs"}handleClick=()=>{if(!this.active){const t=this.parentElement;t&&"K-TABS"===t.tagName&&(t.active=this.for||t.tabs.indexOf(this).toString())}};get tabs(){return"K-TABS"===this.parentElement?.tagName?this.parentElement:null}render(){return t`
|
|
103
103
|
<button id="button" @click=${this.handleClick}>
|
|
104
104
|
<slot></slot>
|
|
105
105
|
</button>
|
|
@@ -131,7 +131,7 @@ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponen
|
|
|
131
131
|
:host([active]) #button {
|
|
132
132
|
color: var(--tc_primary);
|
|
133
133
|
}
|
|
134
|
-
`}export class TabContent extends
|
|
134
|
+
`}export class TabContent extends s{static properties={active:{type:Boolean,reflect:!0,converter:o},name:{type:String,reflect:!0}};constructor(){super(),this.active=!1,this.name=""}get tabs(){return"K-TABS"===this.parentElement?.tagName?this.parentElement:null}render(){return t`<slot></slot>`}static styles=e`
|
|
135
135
|
:host {
|
|
136
136
|
display: block;
|
|
137
137
|
height: 100%;
|
|
@@ -148,7 +148,7 @@ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponen
|
|
|
148
148
|
:host(:not([active])) {
|
|
149
149
|
display: none;
|
|
150
150
|
}
|
|
151
|
-
`}export class TabSpacer extends
|
|
151
|
+
`}export class TabSpacer extends s{constructor(){super(),this.slot="tabs"}static styles=e`
|
|
152
152
|
:host {
|
|
153
153
|
flex: 1 1 auto !important;
|
|
154
154
|
height: 1px;
|