Skip to content

Commit c99e9ed

Browse files
lokeshclaudepre-commit-ci[bot]
authored
New web component ol-chip (#12012)
* Add OLChip component and update facet templates - Imported OLChip component in index.js. - Replaced span elements with ol-chip components in work_search_facets.html for better UI representation of facet entries. - Updated work_search_selected_facets.html to use ol-chip for selected facets, enhancing the display and interaction. - Modified CSS for facets to improve layout and styling, including flex properties for better responsiveness. - Added import for ol-chip styles in page-user.less to ensure proper styling is applied. * Refactor OLChip component and update styles - Renamed event from 'chip-click' to 'ol-chip-select' for clarity. - Simplified CSS properties in OLChip for consistency and readability. - Adjusted padding and font sizes in ol-chip.less for better alignment. - Updated facet template links to use consistent capitalization for "More" and "Less". * feat: Enhance OLChip component and documentation - Introduced CSS variables for padding and icon sizes in OLChip for improved customization. - Updated styles for selected state and small size variations to enhance visual consistency. - Added comprehensive examples and documentation for the OLChip component in design.html, showcasing various use cases including default, selected, small size, and interactive toggle functionalities. * style: Update OLChip selected state color and remove unused examples - Changed the color of the selected state in the OLChip component for better visibility. - Removed unused small size examples from design.html to streamline the documentation and improve clarity. - Added positioning and padding adjustments in legacy.less for better layout consistency. * refactor: Update OlPagination event name and enhance design documentation - Changed the event name from 'update:page' to 'ol-pagination-change' in the OlPagination component for better clarity and consistency. - Updated the event detail structure to include an object with the page number. - Revised design.html to reflect the new event name in examples, improving documentation accuracy. - Enhanced CSS styles in page-design.less for better layout and spacing in the design pattern library. * fix: Update facet handling and add tooltips for better UX - Modified the condition for skipping empty facet counts to improve performance. - Introduced tooltips for facets in the selected facets template to enhance user experience. - Added a comment regarding the handling of the 'public_scan_b' facet for future consideration. * feat: Add OLChipGroup component and update RelatedSubjects macro - Introduced the OLChipGroup component to enhance the grouping of chips in the UI. - Updated the RelatedSubjects macro to utilize OLChipGroup for better visual organization of subject links. - Imported the new OLChip component styles in the page-subject.less file for consistent styling. * Update margin for h3 elements in link-box component * Update OLChip styles: change font family to button and adjust line height for better alignment * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add chip-label prop to OLChip for accessible facet context The facet tooltips (e.g. "Written in", "Published by") were set via the title attribute on the host element, which screen readers can't reach inside shadow DOM. Add a chip-label property that forwards as aria-label to the inner <a>/<button>, so assistive tech announces the full context like "Written in: English". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update stylelint configuration and CSS files - Modify .stylelintrc.json to allow specific ol- types in selector-type-no-unknown rule. - Remove unused import for ol-chip.css in page-user.css to streamline styles. - Change color property in h4.facetHead from a hex value to a CSS variable for better maintainability. * Wrap chip demo labels in design.html with i18n calls Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Toggle chip selection state in OLChip and set role attribute in OLChipGroup for accessibility * Remove ol-chip.css and update imports in page-user.css and page-subject.css. Add pre-hydration styles for ol-chip and ol-read-more components in head.html to prevent layout shifts. * Refactor OLChip component to enhance icon rendering and hover effects - Consolidate check and close icons into a single _renderIcons method. - Update CSS class names for icons to improve clarity and maintainability. - Implement hover effects to toggle icon visibility based on chip selection state. * Refactor OLChip component to improve icon carousel functionality and hover effects - Rename CSS classes for clarity, changing .icon to .icon-slot and introducing .icon-carousel. - Implement a carousel effect for icons on hover, enhancing user interaction. - Adjust icon visibility and transitions to create a smoother experience when selecting the chip. * Enhance documentation and OLChip component functionality - Add a new section on compound components in web-components.md to clarify usage and best practices. - Update README.md to include a link to the new design documentation. - Refine OLChip styles to improve hover effects and responsiveness, ensuring better user interaction across devices. - Update tooltip translations in work_search_selected_facets.html for improved accessibility. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Remove docs/ai and pagination event changes (moved to separate branches) These changes now live in dedicated branches for smaller PRs: - docs/ai/ updates → ai-design branch - OlPagination event rename → pagination-event branch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update work search form and add styling for search-row class - Modified the search form in work_search.html to include an additional class 'search-row'. - Added CSS rules for the 'search-row' class to provide a margin-bottom of 8px for better spacing. * Review fixes: rename chip-label to accessible-label, drop aria-current and will-change, scope p rule Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent fd5f2cd commit c99e9ed

16 files changed

Lines changed: 759 additions & 262 deletions

File tree

.stylelintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"declaration-block-no-shorthand-property-overrides": true,
3434
"selector-pseudo-class-no-unknown": [true, {"ignorePseudoClasses": ["selected"]}],
3535
"selector-pseudo-element-no-unknown": true,
36-
"selector-type-no-unknown": true,
36+
"selector-type-no-unknown": [true, {"ignoreTypes": ["/^ol-/"]}],
3737
"media-feature-name-no-unknown": true,
3838
"at-rule-no-unknown": true,
3939
"comment-no-empty": true,
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import { LitElement, html, css, nothing } from 'lit';
2+
3+
/**
4+
* OLChip - A pill-shaped interactive chip web component
5+
*
6+
* Supports two sizes, a selected state with a checkmark icon,
7+
* click events, and optional link behavior via href.
8+
*
9+
* @property {Boolean} selected - Whether the chip is in a selected state
10+
* @property {String} size - Chip size: "small" or "medium" (default)
11+
* @property {String} href - When set, the chip renders as a link
12+
* @property {String} count - Optional count displayed to the right of the label
13+
* @property {String} accessibleLabel - Override aria-label on the inner interactive element
14+
*
15+
* @fires ol-chip-select - Fired on click. detail: { selected: Boolean }
16+
*
17+
* @example
18+
* <ol-chip>Fiction</ol-chip>
19+
*
20+
* @example
21+
* <ol-chip selected>History</ol-chip>
22+
*
23+
* @example
24+
* <ol-chip size="small" count="76" href="/subjects/fiction">Fiction</ol-chip>
25+
*/
26+
export class OLChip extends LitElement {
27+
static properties = {
28+
selected: { type: Boolean, reflect: true },
29+
size: { type: String, reflect: true },
30+
href: { type: String },
31+
count: { type: String },
32+
accessibleLabel: { type: String, attribute: 'accessible-label' },
33+
};
34+
35+
static styles = css`
36+
:host {
37+
--chip-padding-block: 6px;
38+
--chip-padding-inline: 12px;
39+
--chip-icon-size: 14px;
40+
--chip-icon-gap: 4px;
41+
display: inline-block;
42+
}
43+
44+
:host([size="small"]) {
45+
--chip-padding-block: 4px;
46+
--chip-padding-inline: 8px;
47+
--chip-icon-size: 12px;
48+
}
49+
50+
.chip {
51+
position: relative;
52+
display: inline-flex;
53+
align-items: center;
54+
padding: var(--chip-padding-block) var(--chip-padding-inline);
55+
border: var(--border-width) solid var(--color-border-subtle);
56+
border-radius: var(--border-radius-pill);
57+
font-family: var(--font-family-button);
58+
font-size: var(--font-size-body-medium);
59+
line-height: var(--line-height-chip);
60+
background: var(--white);
61+
color: var(--dark-grey);
62+
cursor: pointer;
63+
user-select: none;
64+
text-decoration: none;
65+
}
66+
67+
@media (hover: hover) and (pointer: fine) {
68+
.chip:hover {
69+
background: var(--lightest-grey);
70+
}
71+
}
72+
73+
.chip:active {
74+
transform: scale(0.97);
75+
}
76+
77+
.chip:focus-visible {
78+
outline: none;
79+
box-shadow: var(--box-shadow-focus);
80+
}
81+
82+
/* Selected state */
83+
:host([selected]) .chip {
84+
padding-inline-start: calc(var(--chip-padding-inline) + var(--chip-icon-size) + var(--chip-icon-gap));
85+
background: var(--primary-blue);
86+
border-color: var(--primary-blue);
87+
color: var(--white);
88+
}
89+
90+
@media (hover: hover) and (pointer: fine) {
91+
:host([selected]) .chip:hover {
92+
background: var(--primary-blue);
93+
filter: brightness(1.1);
94+
}
95+
}
96+
97+
/* Small size */
98+
:host([size="small"]) .chip {
99+
font-size: var(--font-size-label-medium);
100+
}
101+
102+
/* Icon carousel — clips overflow so icons slide in/out */
103+
.icon-slot {
104+
position: absolute;
105+
inset-inline-start: var(--chip-padding-inline);
106+
top: 50%;
107+
transform: translateY(-50%);
108+
width: var(--chip-icon-size);
109+
height: var(--chip-icon-size);
110+
}
111+
112+
.icon-carousel {
113+
display: flex;
114+
flex-direction: column;
115+
transition: transform 0.2s cubic-bezier(.25, .46, .45, .94);
116+
}
117+
118+
@media (hover: hover) and (pointer: fine) {
119+
.chip:hover .icon-carousel {
120+
transform: translateY(-50%);
121+
}
122+
}
123+
124+
.icon {
125+
width: var(--chip-icon-size);
126+
height: var(--chip-icon-size);
127+
flex-shrink: 0;
128+
transition: opacity 0.2s cubic-bezier(.25, .46, .45, .94),
129+
filter 0.2s cubic-bezier(.25, .46, .45, .94);
130+
}
131+
132+
.icon-check {
133+
opacity: 1;
134+
filter: blur(0);
135+
}
136+
137+
.icon-close {
138+
opacity: 0;
139+
filter: blur(2px);
140+
}
141+
142+
@media (hover: hover) and (pointer: fine) {
143+
.chip:hover .icon-check {
144+
opacity: 0;
145+
filter: blur(2px);
146+
}
147+
148+
.chip:hover .icon-close {
149+
opacity: 1;
150+
filter: blur(0);
151+
}
152+
}
153+
154+
/* Count */
155+
.count {
156+
margin-inline-start: 4px;
157+
color: #777;
158+
font-size: 0.85em;
159+
font-variant-numeric: tabular-nums;
160+
}
161+
162+
:host([selected]) .count {
163+
color: #c6e1f0;
164+
}
165+
`;
166+
167+
constructor() {
168+
super();
169+
this.selected = false;
170+
this.size = 'medium';
171+
this.href = null;
172+
this.count = null;
173+
this.accessibleLabel = null;
174+
}
175+
176+
_handleClick() {
177+
this.dispatchEvent(new CustomEvent('ol-chip-select', {
178+
bubbles: true,
179+
composed: true,
180+
detail: { selected: !this.selected },
181+
}));
182+
}
183+
184+
_renderIcons() {
185+
if (!this.selected) return nothing;
186+
187+
return html`
188+
<span class="icon-slot">
189+
<span class="icon-carousel">
190+
<svg
191+
class="icon icon-check"
192+
aria-hidden="true"
193+
viewBox="0 0 24 24"
194+
fill="none"
195+
stroke="currentColor"
196+
stroke-width="3"
197+
stroke-linecap="round"
198+
stroke-linejoin="round"
199+
>
200+
<path d="M20 6 9 17l-5-5"/>
201+
</svg>
202+
<svg
203+
class="icon icon-close"
204+
aria-hidden="true"
205+
viewBox="0 0 24 24"
206+
fill="none"
207+
stroke="currentColor"
208+
stroke-width="3"
209+
stroke-linecap="round"
210+
stroke-linejoin="round"
211+
>
212+
<path d="M18 6 6 18"/><path d="m6 6 12 12"/>
213+
</svg>
214+
</span>
215+
</span>
216+
`;
217+
}
218+
219+
_renderCount() {
220+
if (this.count === null) return nothing;
221+
222+
return html`<span class="count">${this.count}</span>`;
223+
}
224+
225+
render() {
226+
const content = html`
227+
${this._renderIcons()}
228+
<slot></slot>
229+
${this._renderCount()}
230+
`;
231+
232+
if (this.href) {
233+
return html`
234+
<a class="chip" href=${this.href}
235+
aria-label=${this.accessibleLabel || nothing}
236+
@click=${this._handleClick}>
237+
${content}
238+
</a>
239+
`;
240+
}
241+
242+
return html`
243+
<button class="chip" type="button"
244+
aria-label=${this.accessibleLabel || nothing}
245+
aria-pressed=${this.selected}
246+
@click=${this._handleClick}>
247+
${content}
248+
</button>
249+
`;
250+
}
251+
}
252+
253+
customElements.define('ol-chip', OLChip);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { LitElement, html, css } from 'lit';
2+
3+
/**
4+
* OLChipGroup - A flex-wrap container for ol-chip components
5+
*
6+
* Provides consistent spacing and wrapping behavior for groups of chips.
7+
*
8+
* @property {String} gap - Gap size: "small" (4px), "medium" (8px, default), or "large" (12px)
9+
*
10+
* @example
11+
* <ol-chip-group>
12+
* <ol-chip>Fiction</ol-chip>
13+
* <ol-chip>History</ol-chip>
14+
* <ol-chip>Science</ol-chip>
15+
* </ol-chip-group>
16+
*/
17+
export class OLChipGroup extends LitElement {
18+
static properties = {
19+
gap: { type: String, reflect: true },
20+
};
21+
22+
static styles = css`
23+
:host {
24+
display: flex;
25+
flex-wrap: wrap;
26+
gap: 8px;
27+
}
28+
29+
:host([gap="small"]) {
30+
gap: 4px;
31+
}
32+
33+
:host([gap="large"]) {
34+
gap: 12px;
35+
}
36+
`;
37+
38+
constructor() {
39+
super();
40+
this.gap = 'medium';
41+
}
42+
43+
connectedCallback() {
44+
super.connectedCallback();
45+
if (!this.hasAttribute('role')) {
46+
this.setAttribute('role', 'group');
47+
}
48+
}
49+
50+
render() {
51+
return html`<slot></slot>`;
52+
}
53+
}
54+
55+
customElements.define('ol-chip-group', OLChipGroup);

openlibrary/components/lit/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
// Export components (importing also registers them as custom elements)
99
export { OLReadMore } from './OLReadMore.js';
1010
export { OlPagination } from './OlPagination.js';
11+
export { OLChip } from './OLChip.js';
12+
export { OLChipGroup } from './OLChipGroup.js';
1113

0 commit comments

Comments
 (0)