@unofficialbox/box-open-elements 0.1.0
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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/components/actions/button-group.d.ts +22 -0
- package/dist/components/actions/button-group.js +255 -0
- package/dist/components/actions/button.d.ts +16 -0
- package/dist/components/actions/button.js +190 -0
- package/dist/components/actions/icon-button.d.ts +20 -0
- package/dist/components/actions/icon-button.js +187 -0
- package/dist/components/actions/link-button.d.ts +14 -0
- package/dist/components/actions/link-button.js +137 -0
- package/dist/components/actions/menu-item.d.ts +17 -0
- package/dist/components/actions/menu-item.js +137 -0
- package/dist/components/actions/menu.d.ts +22 -0
- package/dist/components/actions/menu.js +178 -0
- package/dist/components/actions/segmented-control.d.ts +27 -0
- package/dist/components/actions/segmented-control.js +273 -0
- package/dist/components/collections/card.d.ts +13 -0
- package/dist/components/collections/card.js +110 -0
- package/dist/components/collections/carousel.d.ts +40 -0
- package/dist/components/collections/carousel.js +406 -0
- package/dist/components/collections/datalist-item.d.ts +32 -0
- package/dist/components/collections/datalist-item.js +196 -0
- package/dist/components/collections/draggable-list.d.ts +33 -0
- package/dist/components/collections/draggable-list.js +306 -0
- package/dist/components/collections/grid-view.d.ts +38 -0
- package/dist/components/collections/grid-view.js +321 -0
- package/dist/components/collections/pagination.d.ts +19 -0
- package/dist/components/collections/pagination.js +147 -0
- package/dist/components/collections/tree-grid.d.ts +47 -0
- package/dist/components/collections/tree-grid.js +593 -0
- package/dist/components/collections/tree.d.ts +37 -0
- package/dist/components/collections/tree.js +526 -0
- package/dist/components/feedback/alert.d.ts +27 -0
- package/dist/components/feedback/alert.js +263 -0
- package/dist/components/feedback/badge.d.ts +12 -0
- package/dist/components/feedback/badge.js +99 -0
- package/dist/components/feedback/chip.d.ts +33 -0
- package/dist/components/feedback/chip.js +261 -0
- package/dist/components/feedback/empty-state.d.ts +19 -0
- package/dist/components/feedback/empty-state.js +137 -0
- package/dist/components/feedback/error-mask.d.ts +25 -0
- package/dist/components/feedback/error-mask.js +199 -0
- package/dist/components/feedback/help-text.d.ts +22 -0
- package/dist/components/feedback/help-text.js +176 -0
- package/dist/components/feedback/nudge.d.ts +32 -0
- package/dist/components/feedback/nudge.js +299 -0
- package/dist/components/feedback/progress-bar.d.ts +18 -0
- package/dist/components/feedback/progress-bar.js +128 -0
- package/dist/components/feedback/progress-ring.d.ts +21 -0
- package/dist/components/feedback/progress-ring.js +155 -0
- package/dist/components/feedback/progress-steps.d.ts +25 -0
- package/dist/components/feedback/progress-steps.js +276 -0
- package/dist/components/feedback/skeleton.d.ts +14 -0
- package/dist/components/feedback/skeleton.js +95 -0
- package/dist/components/feedback/spinner.d.ts +10 -0
- package/dist/components/feedback/spinner.js +80 -0
- package/dist/components/feedback/toast.d.ts +26 -0
- package/dist/components/feedback/toast.js +205 -0
- package/dist/components/files/drop-zone.d.ts +19 -0
- package/dist/components/files/drop-zone.js +169 -0
- package/dist/components/forms/calendar.d.ts +47 -0
- package/dist/components/forms/calendar.js +499 -0
- package/dist/components/forms/category-selector.d.ts +35 -0
- package/dist/components/forms/category-selector.js +269 -0
- package/dist/components/forms/checkbox-group.d.ts +31 -0
- package/dist/components/forms/checkbox-group.js +267 -0
- package/dist/components/forms/checkbox.d.ts +28 -0
- package/dist/components/forms/checkbox.js +250 -0
- package/dist/components/forms/color-picker.d.ts +34 -0
- package/dist/components/forms/color-picker.js +314 -0
- package/dist/components/forms/combobox.d.ts +37 -0
- package/dist/components/forms/combobox.js +234 -0
- package/dist/components/forms/date-field.d.ts +27 -0
- package/dist/components/forms/date-field.js +187 -0
- package/dist/components/forms/dropdown.d.ts +38 -0
- package/dist/components/forms/dropdown.js +405 -0
- package/dist/components/forms/dual-listbox.d.ts +44 -0
- package/dist/components/forms/dual-listbox.js +484 -0
- package/dist/components/forms/fieldset.d.ts +32 -0
- package/dist/components/forms/fieldset.js +168 -0
- package/dist/components/forms/multi-select.d.ts +30 -0
- package/dist/components/forms/multi-select.js +264 -0
- package/dist/components/forms/number-input.d.ts +32 -0
- package/dist/components/forms/number-input.js +245 -0
- package/dist/components/forms/pill-cloud.d.ts +35 -0
- package/dist/components/forms/pill-cloud.js +230 -0
- package/dist/components/forms/pill-selector-dropdown.d.ts +55 -0
- package/dist/components/forms/pill-selector-dropdown.js +499 -0
- package/dist/components/forms/radio-group.d.ts +32 -0
- package/dist/components/forms/radio-group.js +285 -0
- package/dist/components/forms/range-slider.d.ts +36 -0
- package/dist/components/forms/range-slider.js +294 -0
- package/dist/components/forms/rating.d.ts +31 -0
- package/dist/components/forms/rating.js +302 -0
- package/dist/components/forms/rich-text-input.d.ts +32 -0
- package/dist/components/forms/rich-text-input.js +403 -0
- package/dist/components/forms/search-field.d.ts +27 -0
- package/dist/components/forms/search-field.js +293 -0
- package/dist/components/forms/select.d.ts +30 -0
- package/dist/components/forms/select.js +198 -0
- package/dist/components/forms/slider.d.ts +31 -0
- package/dist/components/forms/slider.js +221 -0
- package/dist/components/forms/spin-button.d.ts +33 -0
- package/dist/components/forms/spin-button.js +352 -0
- package/dist/components/forms/switch.d.ts +32 -0
- package/dist/components/forms/switch.js +302 -0
- package/dist/components/forms/tag-input.d.ts +46 -0
- package/dist/components/forms/tag-input.js +420 -0
- package/dist/components/forms/text-area.d.ts +26 -0
- package/dist/components/forms/text-area.js +188 -0
- package/dist/components/forms/text-field.d.ts +24 -0
- package/dist/components/forms/text-field.js +151 -0
- package/dist/components/forms/time-field.d.ts +29 -0
- package/dist/components/forms/time-field.js +203 -0
- package/dist/components/identity/avatar.d.ts +21 -0
- package/dist/components/identity/avatar.js +191 -0
- package/dist/components/identity/contact-datalist-item.d.ts +31 -0
- package/dist/components/identity/contact-datalist-item.js +235 -0
- package/dist/components/identity/persona.d.ts +28 -0
- package/dist/components/identity/persona.js +272 -0
- package/dist/components/layout/app-shell.d.ts +26 -0
- package/dist/components/layout/app-shell.js +258 -0
- package/dist/components/layout/divider.d.ts +12 -0
- package/dist/components/layout/divider.js +119 -0
- package/dist/components/layout/nav-sidebar.d.ts +23 -0
- package/dist/components/layout/nav-sidebar.js +167 -0
- package/dist/components/layout/section.d.ts +20 -0
- package/dist/components/layout/section.js +143 -0
- package/dist/components/layout/sidebar-toggle-button.d.ts +26 -0
- package/dist/components/layout/sidebar-toggle-button.js +137 -0
- package/dist/components/layout/split-view.d.ts +19 -0
- package/dist/components/layout/split-view.js +157 -0
- package/dist/components/navigation/accordion.d.ts +25 -0
- package/dist/components/navigation/accordion.js +253 -0
- package/dist/components/navigation/tabs.d.ts +27 -0
- package/dist/components/navigation/tabs.js +289 -0
- package/dist/components/overlays/dialog.d.ts +26 -0
- package/dist/components/overlays/dialog.js +267 -0
- package/dist/components/overlays/drawer.d.ts +32 -0
- package/dist/components/overlays/drawer.js +323 -0
- package/dist/components/overlays/popover.d.ts +35 -0
- package/dist/components/overlays/popover.js +317 -0
- package/dist/components/overlays/tooltip.d.ts +26 -0
- package/dist/components/overlays/tooltip.js +204 -0
- package/dist/components/visuals/illustration.d.ts +26 -0
- package/dist/components/visuals/illustration.js +319 -0
- package/dist/core/controller.d.ts +11 -0
- package/dist/core/controller.js +23 -0
- package/dist/core/element.d.ts +22 -0
- package/dist/core/element.js +28 -0
- package/dist/core/event-emitter.d.ts +9 -0
- package/dist/core/event-emitter.js +33 -0
- package/dist/core/form-associated.d.ts +63 -0
- package/dist/core/form-associated.js +218 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +4 -0
- package/dist/core/json-schema.d.ts +1 -0
- package/dist/core/json-schema.js +1 -0
- package/dist/foundations/a11y/focus.d.ts +17 -0
- package/dist/foundations/a11y/focus.js +94 -0
- package/dist/foundations/a11y/heading.d.ts +26 -0
- package/dist/foundations/a11y/heading.js +40 -0
- package/dist/foundations/a11y/index.d.ts +5 -0
- package/dist/foundations/a11y/index.js +3 -0
- package/dist/foundations/a11y/keyboard.d.ts +28 -0
- package/dist/foundations/a11y/keyboard.js +77 -0
- package/dist/foundations/geometry/index.d.ts +1 -0
- package/dist/foundations/geometry/index.js +1 -0
- package/dist/foundations/geometry/tokens.d.ts +123 -0
- package/dist/foundations/geometry/tokens.js +154 -0
- package/dist/foundations/icons/box-iconography.d.ts +479 -0
- package/dist/foundations/icons/box-iconography.generated.d.ts +2370 -0
- package/dist/foundations/icons/box-iconography.generated.js +4010 -0
- package/dist/foundations/icons/box-iconography.js +39 -0
- package/dist/foundations/icons/index.d.ts +1 -0
- package/dist/foundations/icons/index.js +1 -0
- package/dist/foundations/motion/index.d.ts +2 -0
- package/dist/foundations/motion/index.js +1 -0
- package/dist/foundations/motion/tokens.d.ts +39 -0
- package/dist/foundations/motion/tokens.js +43 -0
- package/dist/foundations/tokens/box-dark.d.ts +11 -0
- package/dist/foundations/tokens/box-dark.js +46 -0
- package/dist/foundations/tokens/box-defaults.d.ts +5 -0
- package/dist/foundations/tokens/box-defaults.js +52 -0
- package/dist/foundations/tokens/index.d.ts +5 -0
- package/dist/foundations/tokens/index.js +4 -0
- package/dist/foundations/tokens/interaction.d.ts +28 -0
- package/dist/foundations/tokens/interaction.js +72 -0
- package/dist/foundations/tokens/registry.d.ts +14 -0
- package/dist/foundations/tokens/registry.js +92 -0
- package/dist/foundations/tokens/types.d.ts +16 -0
- package/dist/foundations/tokens/types.js +1 -0
- package/dist/foundations/typography/index.d.ts +2 -0
- package/dist/foundations/typography/index.js +1 -0
- package/dist/foundations/typography/tokens.d.ts +76 -0
- package/dist/foundations/typography/tokens.js +27 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +98 -0
- package/dist/patterns/content-explorer/actions/controller.d.ts +12 -0
- package/dist/patterns/content-explorer/actions/controller.js +36 -0
- package/dist/patterns/content-explorer/actions/index.d.ts +2 -0
- package/dist/patterns/content-explorer/actions/index.js +1 -0
- package/dist/patterns/content-explorer/actions/types.d.ts +13 -0
- package/dist/patterns/content-explorer/actions/types.js +1 -0
- package/dist/patterns/content-explorer/adapters/action-menu.d.ts +24 -0
- package/dist/patterns/content-explorer/adapters/action-menu.js +312 -0
- package/dist/patterns/content-explorer/adapters/breadcrumbs.d.ts +15 -0
- package/dist/patterns/content-explorer/adapters/breadcrumbs.js +161 -0
- package/dist/patterns/content-explorer/adapters/item-summary.d.ts +11 -0
- package/dist/patterns/content-explorer/adapters/item-summary.js +72 -0
- package/dist/patterns/content-explorer/adapters/items.d.ts +4 -0
- package/dist/patterns/content-explorer/adapters/items.js +12 -0
- package/dist/patterns/content-explorer/adapters/list.d.ts +28 -0
- package/dist/patterns/content-explorer/adapters/list.js +527 -0
- package/dist/patterns/content-explorer/adapters/table.d.ts +23 -0
- package/dist/patterns/content-explorer/adapters/table.js +467 -0
- package/dist/patterns/content-explorer/adapters/toolbar.d.ts +19 -0
- package/dist/patterns/content-explorer/adapters/toolbar.js +234 -0
- package/dist/patterns/content-explorer/box-transport.d.ts +44 -0
- package/dist/patterns/content-explorer/box-transport.js +229 -0
- package/dist/patterns/content-explorer/collection/controller.d.ts +17 -0
- package/dist/patterns/content-explorer/collection/controller.js +67 -0
- package/dist/patterns/content-explorer/collection/index.d.ts +2 -0
- package/dist/patterns/content-explorer/collection/index.js +1 -0
- package/dist/patterns/content-explorer/collection/types.d.ts +20 -0
- package/dist/patterns/content-explorer/collection/types.js +1 -0
- package/dist/patterns/content-explorer/content-explorer.d.ts +85 -0
- package/dist/patterns/content-explorer/content-explorer.js +745 -0
- package/dist/patterns/content-explorer/contracts.d.ts +32 -0
- package/dist/patterns/content-explorer/contracts.js +114 -0
- package/dist/patterns/content-explorer/controller.d.ts +34 -0
- package/dist/patterns/content-explorer/controller.js +399 -0
- package/dist/patterns/content-explorer/host-bindings.d.ts +50 -0
- package/dist/patterns/content-explorer/host-bindings.js +76 -0
- package/dist/patterns/content-explorer/index.d.ts +18 -0
- package/dist/patterns/content-explorer/index.js +24 -0
- package/dist/patterns/content-explorer/navigation/controller.d.ts +10 -0
- package/dist/patterns/content-explorer/navigation/controller.js +48 -0
- package/dist/patterns/content-explorer/navigation/index.d.ts +2 -0
- package/dist/patterns/content-explorer/navigation/index.js +1 -0
- package/dist/patterns/content-explorer/navigation/types.d.ts +20 -0
- package/dist/patterns/content-explorer/navigation/types.js +1 -0
- package/dist/patterns/content-explorer/schemas.d.ts +6 -0
- package/dist/patterns/content-explorer/schemas.js +120 -0
- package/dist/patterns/content-explorer/selection/controller.d.ts +12 -0
- package/dist/patterns/content-explorer/selection/controller.js +54 -0
- package/dist/patterns/content-explorer/selection/index.d.ts +2 -0
- package/dist/patterns/content-explorer/selection/index.js +1 -0
- package/dist/patterns/content-explorer/selection/types.d.ts +14 -0
- package/dist/patterns/content-explorer/selection/types.js +1 -0
- package/dist/patterns/content-explorer/types.d.ts +209 -0
- package/dist/patterns/content-explorer/types.js +10 -0
- package/dist/patterns/file-request/file-request-builder.d.ts +36 -0
- package/dist/patterns/file-request/file-request-builder.js +344 -0
- package/dist/patterns/file-request/index.d.ts +1 -0
- package/dist/patterns/file-request/index.js +1 -0
- package/dist/patterns/governance/governance-panel.d.ts +40 -0
- package/dist/patterns/governance/governance-panel.js +351 -0
- package/dist/patterns/governance/index.d.ts +1 -0
- package/dist/patterns/governance/index.js +1 -0
- package/dist/patterns/insights/bar-chart.d.ts +43 -0
- package/dist/patterns/insights/bar-chart.js +462 -0
- package/dist/patterns/insights/chart-panel.d.ts +43 -0
- package/dist/patterns/insights/chart-panel.js +436 -0
- package/dist/patterns/insights/donut-chart.d.ts +43 -0
- package/dist/patterns/insights/donut-chart.js +535 -0
- package/dist/patterns/insights/index.d.ts +5 -0
- package/dist/patterns/insights/index.js +5 -0
- package/dist/patterns/insights/line-chart.d.ts +46 -0
- package/dist/patterns/insights/line-chart.js +511 -0
- package/dist/patterns/insights/metric-card.d.ts +36 -0
- package/dist/patterns/insights/metric-card.js +278 -0
- package/dist/patterns/item/bulk-action-bar.d.ts +35 -0
- package/dist/patterns/item/bulk-action-bar.js +325 -0
- package/dist/patterns/item/index.d.ts +4 -0
- package/dist/patterns/item/index.js +4 -0
- package/dist/patterns/item/item-details-panel.d.ts +61 -0
- package/dist/patterns/item/item-details-panel.js +429 -0
- package/dist/patterns/item/item-form.d.ts +54 -0
- package/dist/patterns/item/item-form.js +485 -0
- package/dist/patterns/item/preview-header.d.ts +46 -0
- package/dist/patterns/item/preview-header.js +323 -0
- package/dist/patterns/metadata/contracts.d.ts +75 -0
- package/dist/patterns/metadata/contracts.js +91 -0
- package/dist/patterns/metadata/index.d.ts +4 -0
- package/dist/patterns/metadata/index.js +4 -0
- package/dist/patterns/metadata/metadata-filter-builder.d.ts +43 -0
- package/dist/patterns/metadata/metadata-filter-builder.js +362 -0
- package/dist/patterns/metadata/metadata-inspector.d.ts +31 -0
- package/dist/patterns/metadata/metadata-inspector.js +245 -0
- package/dist/patterns/metadata/schemas.d.ts +5 -0
- package/dist/patterns/metadata/schemas.js +66 -0
- package/dist/patterns/preview/annotation-inspector.d.ts +44 -0
- package/dist/patterns/preview/annotation-inspector.js +380 -0
- package/dist/patterns/preview/annotation-thread.d.ts +37 -0
- package/dist/patterns/preview/annotation-thread.js +338 -0
- package/dist/patterns/preview/annotation-toolbar.d.ts +42 -0
- package/dist/patterns/preview/annotation-toolbar.js +393 -0
- package/dist/patterns/preview/content-preview-adapter.d.ts +13 -0
- package/dist/patterns/preview/content-preview-adapter.js +30 -0
- package/dist/patterns/preview/index.d.ts +6 -0
- package/dist/patterns/preview/index.js +6 -0
- package/dist/patterns/preview/preview-element.d.ts +41 -0
- package/dist/patterns/preview/preview-element.js +429 -0
- package/dist/patterns/preview/provider-adapter.d.ts +36 -0
- package/dist/patterns/preview/provider-adapter.js +29 -0
- package/dist/patterns/search/filter-bar.d.ts +50 -0
- package/dist/patterns/search/filter-bar.js +379 -0
- package/dist/patterns/search/index.d.ts +3 -0
- package/dist/patterns/search/index.js +3 -0
- package/dist/patterns/search/saved-view-picker.d.ts +25 -0
- package/dist/patterns/search/saved-view-picker.js +239 -0
- package/dist/patterns/search/search-results-header.d.ts +34 -0
- package/dist/patterns/search/search-results-header.js +288 -0
- package/dist/patterns/share/access-stats.d.ts +19 -0
- package/dist/patterns/share/access-stats.js +204 -0
- package/dist/patterns/share/collaborator-avatars.d.ts +22 -0
- package/dist/patterns/share/collaborator-avatars.js +214 -0
- package/dist/patterns/share/contracts.d.ts +65 -0
- package/dist/patterns/share/contracts.js +75 -0
- package/dist/patterns/share/index.d.ts +14 -0
- package/dist/patterns/share/index.js +14 -0
- package/dist/patterns/share/invite-collaborators-contracts.d.ts +38 -0
- package/dist/patterns/share/invite-collaborators-contracts.js +1 -0
- package/dist/patterns/share/invite-collaborators-controller.d.ts +40 -0
- package/dist/patterns/share/invite-collaborators-controller.js +86 -0
- package/dist/patterns/share/invite-collaborators-modal.d.ts +46 -0
- package/dist/patterns/share/invite-collaborators-modal.js +465 -0
- package/dist/patterns/share/permission-matrix.d.ts +37 -0
- package/dist/patterns/share/permission-matrix.js +360 -0
- package/dist/patterns/share/presence-contracts.d.ts +26 -0
- package/dist/patterns/share/presence-contracts.js +1 -0
- package/dist/patterns/share/presence-controller.d.ts +31 -0
- package/dist/patterns/share/presence-controller.js +47 -0
- package/dist/patterns/share/presence.d.ts +32 -0
- package/dist/patterns/share/presence.js +255 -0
- package/dist/patterns/share/schemas.d.ts +4 -0
- package/dist/patterns/share/schemas.js +41 -0
- package/dist/patterns/share/share-panel.d.ts +75 -0
- package/dist/patterns/share/share-panel.js +565 -0
- package/dist/patterns/share/unified-share-controller.d.ts +52 -0
- package/dist/patterns/share/unified-share-controller.js +97 -0
- package/dist/patterns/share/unified-share-modal.d.ts +50 -0
- package/dist/patterns/share/unified-share-modal.js +646 -0
- package/dist/patterns/task/index.d.ts +2 -0
- package/dist/patterns/task/index.js +2 -0
- package/dist/patterns/task/review-queue-item.d.ts +45 -0
- package/dist/patterns/task/review-queue-item.js +403 -0
- package/dist/patterns/task/task-assignment-panel.d.ts +50 -0
- package/dist/patterns/task/task-assignment-panel.js +450 -0
- package/package.json +151 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kyle @ Unofficial Box
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# box-open-elements
|
|
2
|
+
|
|
3
|
+
`box-open-elements` is an open, framework-agnostic design system and web component library for Box-style experiences.
|
|
4
|
+
|
|
5
|
+
It is a ground-up rebuild of [`box-open-web-components`](https://github.com/unofficialbox/box-open-web-components), carrying forward that repo's validated architecture, docs, and research — without its accumulated baggage — under a new industry-standard taxonomy:
|
|
6
|
+
|
|
7
|
+
- **Foundations** — design decisions as data: tokens, color, typography, iconography, accessibility, theming
|
|
8
|
+
- **Components** — accessible Web Components for single controls, organized by category
|
|
9
|
+
- **Patterns** — combinations of components that address user objectives with sequences and flows: headless controllers, transport contracts, and composed workflow surfaces, grouped by Box noun
|
|
10
|
+
|
|
11
|
+
See [docs/taxonomy.md](./docs/taxonomy.md) for the canonical model.
|
|
12
|
+
|
|
13
|
+
The guiding idea is unchanged: predictable, extensible building blocks that are easy for both human developers and AI coding assistants to compose.
|
|
14
|
+
|
|
15
|
+
- plain TypeScript modules, no React requirement in the core package
|
|
16
|
+
- state and business logic separate from rendering: controllers and stores, not framework components
|
|
17
|
+
- standard DOM events where a UI layer needs them
|
|
18
|
+
- accessibility semantics and keyboard support as part of the component contract
|
|
19
|
+
- injected transport contracts instead of SDK coupling
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
This package uses Bun as its package manager and task runner.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Common commands
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun run typecheck
|
|
33
|
+
bun run test
|
|
34
|
+
bun run test:coverage
|
|
35
|
+
bun run build
|
|
36
|
+
bun run verify
|
|
37
|
+
bun run docs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`bun run docs` builds the library and serves the component-documentation site at `http://localhost:4600` — browse the full catalog with live previews, events/properties inspectors, and foundations pages.
|
|
41
|
+
|
|
42
|
+
`bun run verify` is the main safety check and runs typecheck, **coverage-gated** tests (`test:coverage`), and build in sequence.
|
|
43
|
+
|
|
44
|
+
## Current state
|
|
45
|
+
|
|
46
|
+
Full catalog parity with the reference repo, plus every scoped gap the research surfaced:
|
|
47
|
+
|
|
48
|
+
- `src/core` — typed event emitter, controller base class, `BaseElement` (in-place shadow DOM render contract), and `FormAssociatedElement` (native form participation + invalid state)
|
|
49
|
+
- `src/foundations/tokens` — the design-system registry (tokens, icons, illustrations), the Box default bundle, and the Box dark bundle, retoned to Box's modernized Blueprint palette with an Inter typography baseline; shared interaction helpers (`interaction.ts`) for focus/hover/active/disabled
|
|
50
|
+
- `src/foundations/motion` — shared duration/easing vocabulary and reduced-motion CSS helper
|
|
51
|
+
- `src/foundations/icons` — the generated Box iconography manifest and alias layer
|
|
52
|
+
- `tools/style-bridge` — CSS/SCSS → BOE token/selector bridge (`bun run style-bridge`; BUE explorer: `bun run style-bridge:bue-explorer`)
|
|
53
|
+
- `src/components` — 72 components across all ten categories, including the Phase 5 gap fills (`box-chip`, `box-divider`, `box-calendar`, `box-tag-input`, `box-nav-sidebar`, `box-sidebar-toggle-button`, `box-grid-view`, `box-fieldset`, `box-section`, `box-error-mask`, `box-draggable-list`, `box-nudge`, `box-pill-cloud`, `box-pill-selector-dropdown`, `box-datalist-item`, `box-contact-datalist-item`, `box-category-selector`)
|
|
54
|
+
- `src/patterns/content-explorer` — the full headless explorer stack (collection, navigation, selection, actions, facade controller, data-source contracts, Box transport, wire schemas) plus the `box-explorer-*` presentation adapters and the composed `box-content-explorer` surface
|
|
55
|
+
- `src/patterns/{search,item,metadata,share,preview,file-request,task,governance,insights}` — all nine composition/workflow areas, including contracts and wire schemas for metadata and share, the provider-neutral preview adapter stack, the pluggable `box-preview-element`, and the share workflows (`box-presence`, `box-invite-collaborators-modal`, `box-unified-share-modal`, `box-access-stats`, `box-collaborator-avatars`)
|
|
56
|
+
- `packages/box-server` — a dependency-free server-side adapter: CCG auth + REST client, Box-backed explorer/share/metadata data sources, DTO mappers, and framework-neutral route handlers (see [docs/integration/box-server.md](./docs/integration/box-server.md))
|
|
57
|
+
- `packages/react` — optional React wrappers (`@box-open-elements/react`); the validated surface ships `BoxButton`, `BoxTextField`, and `BoxSelect`. React, Angular, Vue, and Svelte progress is tracked in [docs/integration/framework-adapters.md](./docs/integration/framework-adapters.md).
|
|
58
|
+
- `storybook/` — a Bun-native workshop: typed stories → identity-guarded extracted JSON → a self-contained, separately-deployable static site, with no Storybook/Vite runtime or consumer dependency (see [storybook/README.md](./storybook/README.md))
|
|
59
|
+
- Docs site + CI — live GitHub Pages deploy, Storybook-backed variant dropdown, and a strict pixel-diff visual-regression gate in CI
|
|
60
|
+
|
|
61
|
+
**Fidelity program**: complete — Batches 0–7, the medium/low audit nits, and the design-heavy leftovers have shipped.
|
|
62
|
+
|
|
63
|
+
Everything in the [components catalog](./docs/components/catalog.md) and [patterns catalog](./docs/patterns/catalog.md) that carries a **built** marker is implemented here with dedicated tests. Remaining catalog entries are intentional generic-component gaps whose current implementations are explorer-bound; future additions are gap-driven rather than phase-gated ports.
|
|
64
|
+
|
|
65
|
+
## Example: foundations + components
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import {
|
|
69
|
+
applyDesignTokens,
|
|
70
|
+
registerBoxDefaultDesignSystem,
|
|
71
|
+
} from "@unofficialbox/box-open-elements/foundations/tokens";
|
|
72
|
+
import { defineBoxButtonElement } from "@unofficialbox/box-open-elements/components/actions/button";
|
|
73
|
+
|
|
74
|
+
registerBoxDefaultDesignSystem({ setActive: true });
|
|
75
|
+
applyDesignTokens(document.documentElement, "box-default");
|
|
76
|
+
defineBoxButtonElement();
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<box-button label="Save" tone="primary"></box-button>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Components consume foundation tokens (`--boe-token-*`) with safe fallbacks, so they render sensibly with no design system registered and restyle automatically when one is active.
|
|
84
|
+
|
|
85
|
+
## Example: headless patterns
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { ExplorerSelectionController } from "@unofficialbox/box-open-elements/patterns/content-explorer/selection";
|
|
89
|
+
|
|
90
|
+
const selection = new ExplorerSelectionController({ selectionMode: "multiple" });
|
|
91
|
+
|
|
92
|
+
selection.subscribe("selectionChanged", ({ selectedItemIds }) => {
|
|
93
|
+
console.log(selectedItemIds);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
selection.setItems([{ id: "1" }, { id: "2" }]);
|
|
97
|
+
selection.toggleSelection("1");
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Workflow patterns begin as headless behavior and gain presentation adapters, so custom React components, Angular templates, Vue SFCs, Svelte components, Web Components, and plain DOM can all consume the same state.
|
|
101
|
+
|
|
102
|
+
## Import contract
|
|
103
|
+
|
|
104
|
+
- root exports: `@unofficialbox/box-open-elements`
|
|
105
|
+
- shared runtime: `@unofficialbox/box-open-elements/core`
|
|
106
|
+
- foundations: `@unofficialbox/box-open-elements/foundations/<module>`
|
|
107
|
+
- components: `@unofficialbox/box-open-elements/components/<category>/<name>`
|
|
108
|
+
- patterns: `@unofficialbox/box-open-elements/patterns/<area>` and `@unofficialbox/box-open-elements/patterns/<area>/<module>`
|
|
109
|
+
|
|
110
|
+
New exports follow the wildcard contract by default instead of adding explicit `package.json` entries. See [docs/api-guidelines.md](./docs/api-guidelines.md).
|
|
111
|
+
|
|
112
|
+
## Documentation
|
|
113
|
+
|
|
114
|
+
The docs index is at [docs/README.md](./docs/README.md). The most important entries:
|
|
115
|
+
|
|
116
|
+
- [Taxonomy](./docs/taxonomy.md)
|
|
117
|
+
- [Architecture](./docs/architecture.md)
|
|
118
|
+
- [API Guidelines](./docs/api-guidelines.md)
|
|
119
|
+
- [Design Tokens](./docs/foundations/tokens.md)
|
|
120
|
+
- [Content Explorer](./docs/patterns/content-explorer.md)
|
|
121
|
+
- [Box Server Integration](./docs/integration/box-server.md)
|
|
122
|
+
|
|
123
|
+
## Contributing
|
|
124
|
+
|
|
125
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup, the `bun run verify` gate, component conventions, the conformance audits, and the PR workflow. Maintainers: see [RELEASING.md](./RELEASING.md) for publishing to npm.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
export interface ButtonGroupOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class BoxButtonGroupElement extends BaseElement {
|
|
7
|
+
static get observedAttributes(): string[];
|
|
8
|
+
private valueInternal;
|
|
9
|
+
private groupEl;
|
|
10
|
+
get label(): string;
|
|
11
|
+
set label(value: string);
|
|
12
|
+
get layout(): "attached" | "separated";
|
|
13
|
+
set layout(value: "attached" | "separated");
|
|
14
|
+
get options(): ButtonGroupOption[];
|
|
15
|
+
set options(value: ButtonGroupOption[]);
|
|
16
|
+
get value(): string;
|
|
17
|
+
set value(nextValue: string);
|
|
18
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
19
|
+
protected renderTemplate(): void;
|
|
20
|
+
protected update(): void;
|
|
21
|
+
}
|
|
22
|
+
export declare const defineBoxButtonGroupElement: (tagName?: string) => typeof BoxButtonGroupElement;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
import { boeRadius } from "../../foundations/geometry/index.js";
|
|
3
|
+
import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
|
|
4
|
+
const DEFAULT_TAG_NAME = "box-button-group";
|
|
5
|
+
const escapeHtml = (value) => value
|
|
6
|
+
.replaceAll("&", "&")
|
|
7
|
+
.replaceAll("<", "<")
|
|
8
|
+
.replaceAll(">", ">")
|
|
9
|
+
.replaceAll('"', """)
|
|
10
|
+
.replaceAll("'", "'");
|
|
11
|
+
const buttonGroupStyles = `
|
|
12
|
+
:host {
|
|
13
|
+
display: inline-block;
|
|
14
|
+
color: inherit;
|
|
15
|
+
font: inherit;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[part="group"] {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: stretch;
|
|
21
|
+
gap: 0.5rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
[part="group"][data-layout="attached"] {
|
|
25
|
+
gap: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[part="button"] {
|
|
29
|
+
appearance: none;
|
|
30
|
+
font: inherit;
|
|
31
|
+
font-weight: 600;
|
|
32
|
+
line-height: 1.2;
|
|
33
|
+
padding: 0.45em 1em;
|
|
34
|
+
border: 1px solid var(--boe-token-stroke-stroke, #e8e8e8);
|
|
35
|
+
border-radius: ${boeRadius.control};
|
|
36
|
+
background: var(--boe-token-surface-surface, #ffffff);
|
|
37
|
+
color: var(--boe-token-text-text, #222222);
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
|
40
|
+
transition:
|
|
41
|
+
background-color ${boeMotionDuration.interactive} ${boeMotionEasing.standard},
|
|
42
|
+
border-color ${boeMotionDuration.interactive} ${boeMotionEasing.standard},
|
|
43
|
+
color ${boeMotionDuration.interactive} ${boeMotionEasing.standard},
|
|
44
|
+
box-shadow ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[part="button"][data-layout="attached"] {
|
|
48
|
+
border-radius: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
[part="button"][data-layout="attached"][data-position="first"] {
|
|
52
|
+
border-top-left-radius: ${boeRadius.control};
|
|
53
|
+
border-bottom-left-radius: ${boeRadius.control};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[part="button"][data-layout="attached"][data-position="last"] {
|
|
57
|
+
border-top-right-radius: ${boeRadius.control};
|
|
58
|
+
border-bottom-right-radius: ${boeRadius.control};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
[part="button"][data-layout="attached"][data-position="only"] {
|
|
62
|
+
border-radius: ${boeRadius.control};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
[part="button"][data-layout="attached"][data-position="middle"],
|
|
66
|
+
[part="button"][data-layout="attached"][data-position="last"] {
|
|
67
|
+
margin-left: -1px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
[part="button"]:not([data-selected="true"]):hover {
|
|
71
|
+
background: var(--boe-token-surface-surface-hover, #f4f4f4);
|
|
72
|
+
border-color: var(--boe-token-stroke-stroke-hover, #bcbcbc);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
[part="button"][data-selected="true"] {
|
|
76
|
+
border-color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 22%, var(--boe-token-stroke-stroke, #e8e8e8) 78%);
|
|
77
|
+
background: var(--boe-token-surface-surface, #ffffff);
|
|
78
|
+
color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 80%, var(--boe-token-text-text, #222222) 20%);
|
|
79
|
+
box-shadow: 0 6px 12px rgba(15, 23, 42, 0.035);
|
|
80
|
+
z-index: 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
[part="button"]:focus-visible {
|
|
84
|
+
outline: none;
|
|
85
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 18%, transparent);
|
|
86
|
+
z-index: 2;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
[part="button"]:disabled {
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
opacity: 0.55;
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
export class BoxButtonGroupElement extends BaseElement {
|
|
95
|
+
static get observedAttributes() {
|
|
96
|
+
return ["label", "layout", "options", "value"];
|
|
97
|
+
}
|
|
98
|
+
valueInternal = "";
|
|
99
|
+
groupEl;
|
|
100
|
+
get label() {
|
|
101
|
+
return this.getAttribute("label") ?? "Button group";
|
|
102
|
+
}
|
|
103
|
+
set label(value) {
|
|
104
|
+
this.setAttribute("label", value);
|
|
105
|
+
}
|
|
106
|
+
get layout() {
|
|
107
|
+
return this.getAttribute("layout") === "attached" ? "attached" : "separated";
|
|
108
|
+
}
|
|
109
|
+
set layout(value) {
|
|
110
|
+
this.setAttribute("layout", value);
|
|
111
|
+
}
|
|
112
|
+
get options() {
|
|
113
|
+
const raw = this.getAttribute("options");
|
|
114
|
+
if (!raw) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(raw);
|
|
119
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
set options(value) {
|
|
126
|
+
this.setAttribute("options", JSON.stringify(value));
|
|
127
|
+
}
|
|
128
|
+
get value() {
|
|
129
|
+
return this.valueInternal;
|
|
130
|
+
}
|
|
131
|
+
set value(nextValue) {
|
|
132
|
+
this.valueInternal = nextValue;
|
|
133
|
+
this.setAttribute("value", nextValue);
|
|
134
|
+
if (this.isRendered) {
|
|
135
|
+
this.update();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
139
|
+
if (name === "value") {
|
|
140
|
+
this.valueInternal = this.getAttribute("value") ?? "";
|
|
141
|
+
}
|
|
142
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
143
|
+
}
|
|
144
|
+
renderTemplate() {
|
|
145
|
+
if (!this.shadowRoot) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.shadowRoot.innerHTML = `
|
|
149
|
+
<style>${buttonGroupStyles}</style>
|
|
150
|
+
<div part="group" role="radiogroup"></div>
|
|
151
|
+
`;
|
|
152
|
+
this.groupEl = this.shadowRoot.querySelector('[part="group"]');
|
|
153
|
+
}
|
|
154
|
+
update() {
|
|
155
|
+
if (!this.groupEl) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const options = this.options;
|
|
159
|
+
const selectedValue = this.valueInternal || options[0]?.value || "";
|
|
160
|
+
if (selectedValue !== this.valueInternal) {
|
|
161
|
+
this.valueInternal = selectedValue;
|
|
162
|
+
this.setAttribute("value", selectedValue);
|
|
163
|
+
}
|
|
164
|
+
this.groupEl.dataset.layout = this.layout;
|
|
165
|
+
this.groupEl.setAttribute("aria-label", this.label);
|
|
166
|
+
// Rebuild the option buttons (their count may have changed)
|
|
167
|
+
this.groupEl.innerHTML = options
|
|
168
|
+
.map((option, index) => {
|
|
169
|
+
const position = options.length === 1
|
|
170
|
+
? "only"
|
|
171
|
+
: index === 0
|
|
172
|
+
? "first"
|
|
173
|
+
: index === options.length - 1
|
|
174
|
+
? "last"
|
|
175
|
+
: "middle";
|
|
176
|
+
return `
|
|
177
|
+
<button
|
|
178
|
+
type="button"
|
|
179
|
+
part="button"
|
|
180
|
+
role="radio"
|
|
181
|
+
data-value="${escapeHtml(option.value)}"
|
|
182
|
+
data-layout="${this.layout}"
|
|
183
|
+
data-position="${position}"
|
|
184
|
+
data-selected="${String(option.value === selectedValue)}"
|
|
185
|
+
aria-checked="${String(option.value === selectedValue)}"
|
|
186
|
+
tabindex="${option.value === selectedValue ? "0" : "-1"}"
|
|
187
|
+
>
|
|
188
|
+
${escapeHtml(option.label)}
|
|
189
|
+
</button>
|
|
190
|
+
`;
|
|
191
|
+
})
|
|
192
|
+
.join("");
|
|
193
|
+
this.groupEl.querySelectorAll('[part="button"]').forEach((button, index) => {
|
|
194
|
+
button.addEventListener("click", () => {
|
|
195
|
+
const nextValue = button.dataset.value ?? "";
|
|
196
|
+
if (!nextValue || nextValue === this.valueInternal) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
this.valueInternal = nextValue;
|
|
200
|
+
this.setAttribute("value", nextValue);
|
|
201
|
+
this.dispatchEvent(new CustomEvent("value-changed", {
|
|
202
|
+
bubbles: true,
|
|
203
|
+
composed: true,
|
|
204
|
+
detail: { value: nextValue },
|
|
205
|
+
}));
|
|
206
|
+
this.update();
|
|
207
|
+
});
|
|
208
|
+
button.addEventListener("keydown", event => {
|
|
209
|
+
const keyboardEvent = event;
|
|
210
|
+
const lastIndex = options.length - 1;
|
|
211
|
+
let nextIndex = index;
|
|
212
|
+
if (keyboardEvent.key === "ArrowRight" || keyboardEvent.key === "ArrowDown") {
|
|
213
|
+
nextIndex = index >= lastIndex ? 0 : index + 1;
|
|
214
|
+
}
|
|
215
|
+
else if (keyboardEvent.key === "ArrowLeft" || keyboardEvent.key === "ArrowUp") {
|
|
216
|
+
nextIndex = index <= 0 ? lastIndex : index - 1;
|
|
217
|
+
}
|
|
218
|
+
else if (keyboardEvent.key === "Home") {
|
|
219
|
+
nextIndex = 0;
|
|
220
|
+
}
|
|
221
|
+
else if (keyboardEvent.key === "End") {
|
|
222
|
+
nextIndex = lastIndex;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
keyboardEvent.preventDefault();
|
|
228
|
+
const nextOption = options[nextIndex];
|
|
229
|
+
if (!nextOption) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.valueInternal = nextOption.value;
|
|
233
|
+
this.setAttribute("value", nextOption.value);
|
|
234
|
+
this.dispatchEvent(new CustomEvent("value-changed", {
|
|
235
|
+
bubbles: true,
|
|
236
|
+
composed: true,
|
|
237
|
+
detail: { value: nextOption.value },
|
|
238
|
+
}));
|
|
239
|
+
this.update();
|
|
240
|
+
queueMicrotask(() => {
|
|
241
|
+
const nextButton = this.groupEl?.querySelectorAll('[part="button"]')[nextIndex];
|
|
242
|
+
nextButton?.focus();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
export const defineBoxButtonGroupElement = (tagName = DEFAULT_TAG_NAME) => {
|
|
249
|
+
const existingElement = customElements.get(tagName);
|
|
250
|
+
if (existingElement) {
|
|
251
|
+
return existingElement;
|
|
252
|
+
}
|
|
253
|
+
customElements.define(tagName, BoxButtonGroupElement);
|
|
254
|
+
return BoxButtonGroupElement;
|
|
255
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
export declare class BoxButtonElement extends BaseElement {
|
|
3
|
+
static get observedAttributes(): string[];
|
|
4
|
+
private buttonEl;
|
|
5
|
+
get disabled(): boolean;
|
|
6
|
+
set disabled(value: boolean);
|
|
7
|
+
get label(): string;
|
|
8
|
+
set label(value: string);
|
|
9
|
+
get size(): string;
|
|
10
|
+
set size(value: string);
|
|
11
|
+
get tone(): string;
|
|
12
|
+
set tone(value: string);
|
|
13
|
+
protected renderTemplate(): void;
|
|
14
|
+
protected update(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare const defineBoxButtonElement: (tagName?: string) => typeof BoxButtonElement;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
import { boeControl, boeRadius, boeSpace } from "../../foundations/geometry/index.js";
|
|
3
|
+
import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
|
|
4
|
+
const DEFAULT_TAG_NAME = "box-button";
|
|
5
|
+
/**
|
|
6
|
+
* Visual language tracks box-ui-elements `.btn` / `.btn-primary`
|
|
7
|
+
* (`src/styles/common/_buttons.scss` + constants/_buttons.scss).
|
|
8
|
+
* Default tone remains `primary` for API stability; `neutral` is the
|
|
9
|
+
* secondary/bordered BUE default look.
|
|
10
|
+
*/
|
|
11
|
+
const buttonStyles = `
|
|
12
|
+
:host {
|
|
13
|
+
display: inline-block;
|
|
14
|
+
color: inherit;
|
|
15
|
+
font: inherit;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
button {
|
|
19
|
+
appearance: none;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
gap: ${boeSpace[2]};
|
|
25
|
+
min-height: ${boeControl.height};
|
|
26
|
+
padding: 0 ${boeControl.paddingInline};
|
|
27
|
+
font-family: inherit;
|
|
28
|
+
font-size: ${boeControl.fontSize};
|
|
29
|
+
font-weight: 700;
|
|
30
|
+
line-height: 1;
|
|
31
|
+
letter-spacing: ${boeControl.letterSpacing};
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
border-radius: ${boeRadius.control};
|
|
34
|
+
border: 1px solid var(--boe-token-surface-surface-brand, #0061d5);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
background: var(--boe-token-surface-surface-brand, #0061d5);
|
|
37
|
+
color: var(--boe-token-text-text-on-brand, #ffffff);
|
|
38
|
+
box-shadow: none;
|
|
39
|
+
transition:
|
|
40
|
+
background-color ${boeMotionDuration.fast} ${boeMotionEasing.standard},
|
|
41
|
+
border-color ${boeMotionDuration.fast} ${boeMotionEasing.standard},
|
|
42
|
+
color ${boeMotionDuration.fast} ${boeMotionEasing.standard},
|
|
43
|
+
box-shadow ${boeMotionDuration.fast} ${boeMotionEasing.standard};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
button:hover:not(:disabled) {
|
|
47
|
+
background: var(--boe-token-surface-surface-brand-hover, #006ae9);
|
|
48
|
+
border-color: var(--boe-token-surface-surface-brand-hover, #006ae9);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
button:active:not(:disabled) {
|
|
52
|
+
background: var(--boe-token-surface-surface-brand-pressed, #004eac);
|
|
53
|
+
border-color: var(--boe-token-surface-surface-brand-pressed, #004eac);
|
|
54
|
+
box-shadow: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
button:focus-visible {
|
|
58
|
+
outline: none;
|
|
59
|
+
background: var(--boe-token-surface-surface-brand-hover, #006ae9);
|
|
60
|
+
border-color: var(--boe-token-surface-surface-brand, #0061d5);
|
|
61
|
+
box-shadow: ${boeControl.primaryFocusShadow};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
button[data-tone="neutral"] {
|
|
65
|
+
background: var(--boe-token-surface-surface, #ffffff);
|
|
66
|
+
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
67
|
+
border-color: ${boeControl.buttonBorder};
|
|
68
|
+
box-shadow: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
button[data-tone="neutral"]:hover:not(:disabled) {
|
|
72
|
+
background: color-mix(in srgb, var(--boe-token-surface-surface, #ffffff) 97%, black 3%);
|
|
73
|
+
border-color: ${boeControl.buttonBorder};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
button[data-tone="neutral"]:active:not(:disabled) {
|
|
77
|
+
background: color-mix(in srgb, var(--boe-token-surface-surface, #ffffff) 92%, black 8%);
|
|
78
|
+
border-color: ${boeControl.buttonBorder};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
button[data-tone="neutral"]:focus-visible {
|
|
82
|
+
border-color: var(--boe-token-text-text, #222222);
|
|
83
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 10%);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
button[data-tone="danger"] {
|
|
87
|
+
background: var(--boe-token-surface-status-surface-error, #ed3757);
|
|
88
|
+
border-color: var(--boe-token-surface-status-surface-error, #ed3757);
|
|
89
|
+
color: var(--boe-token-text-text-on-brand, #ffffff);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
button[data-tone="danger"]:hover:not(:disabled) {
|
|
93
|
+
background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 92%, white 8%);
|
|
94
|
+
border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 92%, white 8%);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
button[data-tone="danger"]:active:not(:disabled) {
|
|
98
|
+
background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 88%, black 12%);
|
|
99
|
+
border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 88%, black 12%);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
button[data-tone="danger"]:focus-visible {
|
|
103
|
+
box-shadow: inset 0 0 0 1px rgb(255 255 255 / 80%), 0 1px 2px rgb(0 0 0 / 10%);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
button[data-size="small"] {
|
|
107
|
+
min-height: 28px;
|
|
108
|
+
padding: 0 ${boeSpace[3]};
|
|
109
|
+
font-size: 12px;
|
|
110
|
+
border-radius: ${boeRadius.control};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
button[data-size="large"] {
|
|
114
|
+
min-height: ${boeControl.heightLarge};
|
|
115
|
+
padding: 0 ${boeSpace[5]};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
button:disabled {
|
|
119
|
+
cursor: default;
|
|
120
|
+
opacity: ${boeControl.disabledOpacity};
|
|
121
|
+
box-shadow: none;
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
export class BoxButtonElement extends BaseElement {
|
|
125
|
+
static get observedAttributes() {
|
|
126
|
+
return ["disabled", "label", "size", "tone"];
|
|
127
|
+
}
|
|
128
|
+
buttonEl;
|
|
129
|
+
get disabled() {
|
|
130
|
+
return this.hasAttribute("disabled");
|
|
131
|
+
}
|
|
132
|
+
set disabled(value) {
|
|
133
|
+
if (value) {
|
|
134
|
+
this.setAttribute("disabled", "");
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.removeAttribute("disabled");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
get label() {
|
|
141
|
+
return this.getAttribute("label") ?? "Button";
|
|
142
|
+
}
|
|
143
|
+
set label(value) {
|
|
144
|
+
this.setAttribute("label", value);
|
|
145
|
+
}
|
|
146
|
+
get size() {
|
|
147
|
+
return this.getAttribute("size") ?? "medium";
|
|
148
|
+
}
|
|
149
|
+
set size(value) {
|
|
150
|
+
this.setAttribute("size", value);
|
|
151
|
+
}
|
|
152
|
+
get tone() {
|
|
153
|
+
return this.getAttribute("tone") ?? "primary";
|
|
154
|
+
}
|
|
155
|
+
set tone(value) {
|
|
156
|
+
this.setAttribute("tone", value);
|
|
157
|
+
}
|
|
158
|
+
renderTemplate() {
|
|
159
|
+
if (!this.shadowRoot) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.shadowRoot.innerHTML = `
|
|
163
|
+
<style>${buttonStyles}</style>
|
|
164
|
+
<button type="button" part="button"></button>
|
|
165
|
+
`;
|
|
166
|
+
this.buttonEl = this.shadowRoot.querySelector('[part="button"]');
|
|
167
|
+
}
|
|
168
|
+
update() {
|
|
169
|
+
if (!this.buttonEl) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.buttonEl.dataset.tone = this.tone;
|
|
173
|
+
this.buttonEl.dataset.size = this.size;
|
|
174
|
+
if (this.disabled) {
|
|
175
|
+
this.buttonEl.setAttribute("disabled", "");
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.buttonEl.removeAttribute("disabled");
|
|
179
|
+
}
|
|
180
|
+
this.buttonEl.textContent = this.label;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export const defineBoxButtonElement = (tagName = DEFAULT_TAG_NAME) => {
|
|
184
|
+
const existingElement = customElements.get(tagName);
|
|
185
|
+
if (existingElement) {
|
|
186
|
+
return existingElement;
|
|
187
|
+
}
|
|
188
|
+
customElements.define(tagName, BoxButtonElement);
|
|
189
|
+
return BoxButtonElement;
|
|
190
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
export declare class BoxIconButtonElement extends BaseElement {
|
|
3
|
+
private readonly handleDesignSystemChange;
|
|
4
|
+
static get observedAttributes(): string[];
|
|
5
|
+
private buttonEl;
|
|
6
|
+
private iconEl;
|
|
7
|
+
get disabled(): boolean;
|
|
8
|
+
set disabled(value: boolean);
|
|
9
|
+
get icon(): string;
|
|
10
|
+
set icon(value: string);
|
|
11
|
+
get label(): string;
|
|
12
|
+
set label(value: string);
|
|
13
|
+
get tone(): string;
|
|
14
|
+
set tone(value: string);
|
|
15
|
+
connectedCallback(): void;
|
|
16
|
+
disconnectedCallback(): void;
|
|
17
|
+
protected renderTemplate(): void;
|
|
18
|
+
protected update(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare const defineBoxIconButtonElement: (tagName?: string) => typeof BoxIconButtonElement;
|