Skip to content

Commit ced3f94

Browse files
committed
Implement common-picker and stacked layout manager
1 parent dcddde5 commit ced3f94

File tree

9 files changed

+2919
-2799
lines changed

9 files changed

+2919
-2799
lines changed

typescript/package-lock.json

Lines changed: 70 additions & 2226 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

typescript/packages/lookslike-high-level/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ export * as CommonDroppable from "./common-droppable.js";
1313
export * as CommonDraggable from "./common-draggable.js";
1414
export * as CommonSpellEditor from "./common-spell-editor.js";
1515
export * as CommonMermaid from "./mermaid.js";
16+
export * as CommonPicker from "./picker.js";
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { LitElement, html, css } from "lit-element";
2+
import { customElement, property } from "lit/decorators.js";
3+
4+
interface Item {
5+
value: string;
6+
label: string;
7+
}
8+
9+
@customElement("common-picker")
10+
export default class PickerElement extends LitElement {
11+
@property({ type: Array }) items: Item[] = [];
12+
@property({ type: String, reflect: true }) value = "";
13+
@property({ type: String }) filter = "";
14+
@property({ type: Boolean }) hasFocus = false;
15+
16+
static override styles = css`
17+
:host {
18+
display: block;
19+
position: relative;
20+
}
21+
22+
.picker {
23+
position: relative;
24+
}
25+
26+
input {
27+
width: 100%;
28+
padding: 8px;
29+
border: 1px solid #ccc;
30+
border-radius: 4px;
31+
}
32+
33+
.dropdown {
34+
position: absolute;
35+
top: 100%;
36+
left: 0;
37+
right: 0;
38+
max-height: 200px;
39+
overflow-y: auto;
40+
background: white;
41+
border: 1px solid #ccc;
42+
border-top: none;
43+
border-radius: 0 0 4px 4px;
44+
display: none;
45+
}
46+
47+
.dropdown.show {
48+
display: block;
49+
}
50+
51+
.item {
52+
padding: 8px;
53+
cursor: pointer;
54+
}
55+
56+
.item:hover {
57+
background: #f5f5f5;
58+
}
59+
60+
.selected-value {
61+
margin-top: 8px;
62+
padding: 4px;
63+
color: #666;
64+
}
65+
`;
66+
67+
private get filteredItems() {
68+
const filterLower = this.filter.toLowerCase();
69+
return this.items.filter(
70+
item =>
71+
item.label.toLowerCase().includes(filterLower) ||
72+
item.value.toString().toLowerCase().includes(filterLower),
73+
);
74+
}
75+
76+
private handleInput(e: Event) {
77+
const input = e.target as HTMLInputElement;
78+
this.filter = input.value;
79+
}
80+
81+
private handleFocus() {
82+
this.hasFocus = true;
83+
}
84+
85+
private handleBlur() {
86+
this.hasFocus = false;
87+
}
88+
89+
private selectItem(item: Item) {
90+
this.value = item.value;
91+
this.filter = item.label;
92+
this.hasFocus = false;
93+
this.dispatchEvent(
94+
new CustomEvent("pick", {
95+
detail: item,
96+
bubbles: true,
97+
composed: true,
98+
}),
99+
);
100+
}
101+
102+
override render() {
103+
const showDropdown = this.hasFocus;
104+
const items = this.filteredItems;
105+
const selectedItem = this.items.find(item => item.value === this.value);
106+
107+
return html`
108+
<div class="picker">
109+
<input
110+
type="text"
111+
.value=${this.filter}
112+
@input=${this.handleInput}
113+
@focus=${this.handleFocus}
114+
@blur=${this.handleBlur}
115+
placeholder="Search..."
116+
/>
117+
<div class="dropdown ${showDropdown ? "show" : ""}">
118+
${items.map(
119+
item => html`
120+
<div class="item" @mousedown=${this.selectItem.bind(this, item)}>
121+
${item.label}
122+
</div>
123+
`,
124+
)}
125+
</div>
126+
</div>
127+
`;
128+
}
129+
}

typescript/packages/lookslike-high-level/src/data.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,15 @@ import { emailComposer } from "./spells/15_email_composer.jsx";
5858
import { addressBook } from "./spells/16_contacts.jsx";
5959
import { formTest } from "./spells/17_complex_form.jsx";
6060
import { musicLibrary } from "./spells/18_music.jsx";
61-
import { spellManager } from './spells/19_process_manager.jsx'
62-
import { shaderManager } from './spells/20_shader_editor.jsx'
63-
import { schemaGenerator } from './spells/21_model_builder.jsx'
64-
import { search } from './spells/22_search.jsx'
65-
import { notebook } from './spells/23_notes.jsx'
66-
import { quotedb } from './spells/24_quotes.jsx'
67-
import { activity } from './spells/25_activity.jsx'
61+
import { spellManager } from "./spells/19_process_manager.jsx";
62+
import { shaderManager } from "./spells/20_shader_editor.jsx";
63+
import { schemaGenerator } from "./spells/21_model_builder.jsx";
64+
import { search } from "./spells/22_search.jsx";
65+
import { notebook } from "./spells/23_notes.jsx";
66+
import { quotedb } from "./spells/24_quotes.jsx";
67+
import { activity } from "./spells/25_activity.jsx";
6868
import { activityRef } from "./sugar/activity.js";
69+
import { stackLayout } from "./spells/26_stacks.jsx";
6970

7071
export type Charm = {
7172
[NAME]?: string;
@@ -269,6 +270,7 @@ addCharms([
269270
notebook.spawn({ notes: 1 }),
270271
quotedb.spawn({ quotes: 1 }),
271272
activity.spawn(activityRef),
273+
stackLayout.spawn({ stack: 1 }),
272274
FetchService.spawn() as any,
273275
GmailService.spawn() as any,
274276
ViewService.spawn() as any,

0 commit comments

Comments
 (0)