Generated Computers
Locals는 Apple Silicon 엔진으로 로컬 LLM을 최대 3배 빠르게 실행하는 Generated Computers 제품
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A modern, framework-agnostic multi-select dropdown component built as a web component. Features RTL language support, async search, flexible data handling, form integration, multiple display modes, and extensive SCSS customization.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A lightweight, themeable multi-select web component with typeahead search, RTL support, rich content, and full keyboard navigation.
--ms-* variables, dark mode, cascade layers, Theme Designer integration.@keenmate/web-multiselect is a custom element (<web-multiselect>) that turns a list of options into a searchable, themeable multi-select dropdown. Framework-agnostic — works in React, Vue, Svelte, Blazor, plain HTML.
Reads the --base-* tokens from @keenmate/base-css-variables 2.0 when the page loads them (the shared layer behind pure-admin and the Theme Designer), falls back to sensible OS-aware defaults otherwise, and ships with first-class dark-mode and per-instance theming.
Headline features:
<option> / <optgroup> markup — no JavaScript required for simple cases.A major release — breaking, no aliases. The callbacks, events and inputs follow the shared
KeenMate interaction model and naming rulebook (@keenmate/web-components-core 1.0.0-rc17), so
code written for 2.x needs updating. Upgrade guide: the
3.0.0-rc01 release notes; full old → new tables: the
CHANGELOG 3.0.0-rc01 section; step-by-step:
ai/migration-guide.txt.
Breaking changes:
ctx — per-option callbacks read ctx.option (row callbacks also
ctx.optionIndex), e.g. getDisplayValueCallback: ({ option }) => option.name; every ctx
carries controller / element. Before-hooks cancel with false
(beforeSelectCallback, beforeAddCallback (was addNewCallback), beforeKeydownCallback
(was keydownCallback)). on* properties receive the event detail. Custom action
buttons use id + onClick(detail); a new action event reports every button /
data-action click; the toggle state is isToggled / getIsToggledCallback.isMultiple, shouldCloseOnSelect, name, isDisabledMember /
is-disabled-member, maxVisibleBadgeCount, virtualScrollItemHeight, … (attributes derived
from the property names).labels — search-placeholder, select-placeholder, empty-message,
loading-message, add-new-text, … are gone; set labels (property or JSON attribute,
labels='{"selectPlaceholder":"Pick a country"}'). Empty states are noData / noResults.value / defaultValue — was initial-values / initialValues; parsed
per value-format; el.value is the live submitted value. value-format="csv" → text
(joined by the new value-separator).form.reset() restores the initial selection — it used to clear it; it does so without firing
deselect / change.selectedOptions / selectedValue / selectedOption /
searchTerm on the element and el.controller (was getSelected() / getValue() /
selectedItem / ); (was ; action id
and label / ).Also new: the motion level (motion="none | snappy | smooth", data-motion on a section,
window.components.motion), list scrolling that never moves the page, responsive rules (below),
disabled / readonly, open / close /
value-format-error events, getOptionByValue(), the shared loader (renderLoadingCallback),
standalone colours that follow the base-css-variables contract (accent #3b82f6; disabled rows
are tinted).
Earlier releases: 2.6.0-rc03, 2.6.0-rc02, CHANGELOG.
npm install @keenmate/web-multiselect
Declarative — no JavaScript required:
<script type="module">
import '@keenmate/web-multiselect';
</script>
<web-multiselect labels='{"selectPlaceholder": "Pick a country"}'>
<option value="cz">Czech Republic</option>
<option value="sk">Slovakia</option>
<option value="at">Austria</option>
</web-multiselect>
Programmatic — dynamic data + events:
<web-multiselect id="picker" labels='{"searchPlaceholder": "Search…"}'></web-multiselect>
<script type="module">
import '@keenmate/web-multiselect';
const picker = document.getElementById('picker');
picker.options = [
{ value: 'js', label: 'JavaScript', icon: '🟨' },
{ value: 'ts', label: 'TypeScript', icon: '🔷' },
{ value: 'py', label: 'Python', icon: '🐍' }
];
picker.addEventListener('change', (e) => {
console.log('Selected:', e.detail.selectedValues);
});
</script>
See docs/usage.md for the full API and docs/examples.md for advanced patterns (async data, virtual scrolling, custom rendering, form integration).
Tune what the picker does per device or window width without app-side viewport code — a map
of partial configs, or a callback that computes one. A map has two axes, each keyed
mobile / tablet / desktop:
device — the device class (classifyDevice): a phone / tablet by capability
(touch-primary, then the short side); a mouse device is desktop at any width.breakpoint — the window width bucket (768 / 1024px lines, --base-breakpoint-*):
a narrowed desktop window is mobile below 768px.Within one map the breakpoint entry applies first and the device entry over it (device wins
on the same key). Own widths or combinations (ctx.env.viewportWidth, device class AND
width, …) go in a responsiveCallback. Keys are configKeys; set them page-wide, per tag
or per instance
(the generic core mechanism, core SPEC §6.7):
// page-wide (every KeenMate component) and per tag — may be set before the script loads
window.components.responsive = { device: { mobile: { presentation: 'fullscreen' } } };
window.components['web-multiselect'].responsiveCallback = (ctx) =>
ctx.deviceClass === 'mobile' ? { actionsLayout: 'wrap' } : undefined;
// per instance (property, or the JSON attribute responsive='{"device":{"tablet":{…}}}')
el.responsive = {
device: { tablet: { presentation: 'fullscreen' } }, // a touch tablet
breakpoint: { mobile: { badgesDisplayMode: 'count' } }, // any window under 768px
};
el.responsiveCallback = (ctx) => (ctx.env.orientation === 'landscape' ? { badgesThreshold: 5 } : undefined);
Precedence (later wins, key by key): global map → global callback → per-tag map → per-tag
callback → the instance's own attributes / properties → instance map → instance callback.
An attribute written on an element is never overridden by a page rule; null from the
instance callback ignores every page rule. Maps re-run when the device class / breakpoint
changes, callbacks also on every viewport resize; overrides never reflect to attributes. The
pre-rc15 device-keyed shape ({ mobile: … }) warns and is ignored. Typed as MultiSelectResponsiveMap /
MultiSelectResponsiveCallback. Demo: examples-responsive.html, examples-action-buttons.html.
The package ships editor metadata so you get autocomplete and hover docs for the
element's attributes, events, and all --ms-* CSS custom properties. All of it is
generated from the component's source on every build, so it never drifts.
JetBrains (WebStorm / IntelliJ) — works automatically. The IDE discovers
web-types.json via the web-types field in package.json; no setup needed.
VS Code — the data files ship but VS Code doesn't auto-discover them from a
dependency, so point your workspace at them once in .vscode/settings.json:
{
"html.customData": [
"./node_modules/@keenmate/web-multiselect/vscode.html-custom-data.json"
],
"css.customData": [
"./node_modules/@keenmate/web-multiselect/vscode.css-custom-data.json"
]
}
html.customData powers tag/attribute completion on <web-multiselect>;
css.customData powers completion for the --ms-* theming variables. Reload
the window after adding them.
These inputs are inserted as raw HTML — intentionally not XSS-safe, so you control the markup. Sanitize any untrusted text before passing it in:
| Input | Output used in |
|---|---|
labels.noData, labels.noResults, labels.searching | Dropdown empty / searching text (innerHTML) |
labels.addNew, labels.addNewPending | "Add new" prompt (innerHTML; the {value} typed text is escaped) |
labels.selectedCount, labels.moreCount | Counter badge text (innerHTML) |
renderOptionContentCallback, renderGroupLabelContentCallback, renderBadgeContentCallback, renderBadgeCallback, renderSelectedItemContentCallback (string return) | Option rows, group headers, badges, selected panels (innerHTML) |
All other labels (ARIA labels, tooltips, placeholders, popover title, action-button texts) are
plain text, as are showMessage() strings and renderSelectedContentCallback (the closed input's value); option data (values, display values) is escaped.
Modern evergreen browsers — the standalone colour fallbacks use CSS relative-colour syntax (oklch(from …)), the same floor as @keenmate/base-css-variables 2.x:
No polyfills are shipped. SSR-safe: the module imports without crashing in Node, but renders only after hydration in the browser.
# Install dependencies
npm install
# Start dev server (HMR)
npm run dev
# Build for production
npm run build
# Create package tarball
npm run package
# Run tests
npm run test:unit # Vitest (happy-dom) — fast logic checks
npm run test:e2e # Playwright (browser) — interaction/visual
npm test # both
Follows the BlissFramework four-layer web-component layout:
| Layer | File | Role |
|---|---|---|
| Element | src/web-component.ts | MultiSelectElement — custom-element I/O wrapper, driven by the INPUTS table (attributes, properties, callbacks) and the events table |
| Logic | src/multiselect.ts | MultiSelectEngine<T> — framework-agnostic core (search, selection, keyboard, rendering) |
| Service | src/virtual-scroll.ts, src/tree/ | VirtualScroll; the ltree option model and checkbox cascade for tree mode |
| Side | src/types.ts, src/option-formats.ts, src/converters.ts, src/logger.ts, src/index.ts | types, data-options parsers, component-local converters, logging shim, package entry |
Positioning (dropdown, popovers, tooltips), attribute parsing and reflection, and the logging engine come from @keenmate/web-components-core.
Two deviations from the canonical shape, both intentional:
MultiSelectElement extends BlissElement, not HTMLElement directly. Core's BlissElement resolves to HTMLElement in the browser and to a stub class under SSR (typeof HTMLElement === 'undefined'), so importing the module in Node doesn't throw. A literal grep "extends HTMLElement" structure check will not match here by design.src/vite-env.d.ts is a standard Vite ambient-types file, not part of the four-layer model.MIT — see LICENSE.
Follows the BlissFramework component guidelines for structure, theming, color-scheme, and accessibility. Per-check verifications run via /validate-web-component.
Created by Keenmate as part of the Pure Admin design system.
searchTextel.controller.clearSelection()clearAll()clear-selectionlabels.clearSelectionvalue / label / group / icon / subtitle /
disabled, so [{ value, label }] works without configuration; a get*Callback always beats its member.presentation — was mobile-presentation; the mobile width breakpoint is 768px (was 640).el.release() (was el.ready()), host attribute ready +
:state(ready) (was is-ready), el.whenReady(), property shouldDefer.show-debug-info and the debug panel (use el.enableLogging()),
--ms-transition-fast (one duration: --ms-transition-normal), the component's own
prefers-reduced-motion block (core applies reduced motion on every page; the 1.5s loader
slowdown needs base-css-variables).