@vielzeug/refine 3.2.0 → 3.3.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/dist/chip.cjs +9 -9
- package/dist/chip.cjs.map +1 -1
- package/dist/chip.js +38 -35
- package/dist/chip.js.map +1 -1
- package/dist/command-palette.cjs +5 -5
- package/dist/command-palette.cjs.map +1 -1
- package/dist/command-palette.js +5 -5
- package/dist/command-palette.js.map +1 -1
- package/dist/content/card/card.css.cjs +1 -1
- package/dist/content/card/card.css.cjs.map +1 -1
- package/dist/content/card/card.css.js +1 -1
- package/dist/content/card/card.css.js.map +1 -1
- package/dist/content/index.d.ts +4 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/keyboard-key/keyboard-key.css.cjs +2 -0
- package/dist/content/keyboard-key/keyboard-key.css.cjs.map +1 -0
- package/dist/content/keyboard-key/keyboard-key.css.js +6 -0
- package/dist/content/keyboard-key/keyboard-key.css.js.map +1 -0
- package/dist/content/keyboard-key/keyboard-key.d.ts +12 -0
- package/dist/content/keyboard-key/keyboard-key.d.ts.map +1 -0
- package/dist/content/keyboard-key/keyboard-shortcut.css.cjs +2 -0
- package/dist/content/keyboard-key/keyboard-shortcut.css.cjs.map +1 -0
- package/dist/content/keyboard-key/keyboard-shortcut.css.js +6 -0
- package/dist/content/keyboard-key/keyboard-shortcut.css.js.map +1 -0
- package/dist/content/qr-code/qr-code.css.cjs +2 -0
- package/dist/content/qr-code/qr-code.css.cjs.map +1 -0
- package/dist/content/qr-code/qr-code.css.js +6 -0
- package/dist/content/qr-code/qr-code.css.js.map +1 -0
- package/dist/content/qr-code/qr-code.d.ts +74 -0
- package/dist/content/qr-code/qr-code.d.ts.map +1 -0
- package/dist/content/stepper/step.css.cjs +1 -1
- package/dist/content/stepper/step.css.cjs.map +1 -1
- package/dist/content/stepper/step.css.js +1 -1
- package/dist/content/stepper/step.css.js.map +1 -1
- package/dist/counter.cjs +91 -0
- package/dist/counter.cjs.map +1 -0
- package/dist/counter.js +180 -0
- package/dist/counter.js.map +1 -0
- package/dist/custom-elements.json +3838 -3117
- package/dist/disclosure/tabs/tabs.css.cjs +1 -1
- package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
- package/dist/disclosure/tabs/tabs.css.js +1 -1
- package/dist/disclosure/tabs/tabs.css.js.map +1 -1
- package/dist/feedback/chip/chip.css.cjs +1 -1
- package/dist/feedback/chip/chip.css.cjs.map +1 -1
- package/dist/feedback/chip/chip.css.js +1 -1
- package/dist/feedback/chip/chip.css.js.map +1 -1
- package/dist/feedback/chip/chip.d.ts +6 -2
- package/dist/feedback/chip/chip.d.ts.map +1 -1
- package/dist/feedback/progress/progress.css.cjs +1 -1
- package/dist/feedback/progress/progress.css.cjs.map +1 -1
- package/dist/feedback/progress/progress.css.js +1 -1
- package/dist/feedback/progress/progress.css.js.map +1 -1
- package/dist/feedback/progress/progress.d.ts +6 -0
- package/dist/feedback/progress/progress.d.ts.map +1 -1
- package/dist/frameworks/elements.d.ts +1 -1
- package/dist/inputs/button/button.css.cjs +1 -1
- package/dist/inputs/button/button.css.cjs.map +1 -1
- package/dist/inputs/button/button.css.js +1 -1
- package/dist/inputs/button/button.css.js.map +1 -1
- package/dist/inputs/checkbox/checkbox.css.cjs +1 -1
- package/dist/inputs/checkbox/checkbox.css.cjs.map +1 -1
- package/dist/inputs/checkbox/checkbox.css.js +1 -1
- package/dist/inputs/checkbox/checkbox.css.js.map +1 -1
- package/dist/inputs/counter/counter.css.cjs +2 -0
- package/dist/inputs/counter/counter.css.cjs.map +1 -0
- package/dist/inputs/counter/counter.css.js +6 -0
- package/dist/inputs/counter/counter.css.js.map +1 -0
- package/dist/inputs/counter/counter.d.ts +100 -0
- package/dist/inputs/counter/counter.d.ts.map +1 -0
- package/dist/inputs/index.d.ts +4 -0
- package/dist/inputs/index.d.ts.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.cjs +1 -1
- package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.js +1 -1
- package/dist/inputs/message-composer/message-composer.css.js.map +1 -1
- package/dist/inputs/qr-scanner/qr-scanner.css.cjs +2 -0
- package/dist/inputs/qr-scanner/qr-scanner.css.cjs.map +1 -0
- package/dist/inputs/qr-scanner/qr-scanner.css.js +6 -0
- package/dist/inputs/qr-scanner/qr-scanner.css.js.map +1 -0
- package/dist/inputs/qr-scanner/qr-scanner.d.ts +87 -0
- package/dist/inputs/qr-scanner/qr-scanner.d.ts.map +1 -0
- package/dist/inputs/radio/radio.css.cjs +1 -1
- package/dist/inputs/radio/radio.css.cjs.map +1 -1
- package/dist/inputs/radio/radio.css.js +1 -1
- package/dist/inputs/radio/radio.css.js.map +1 -1
- package/dist/inputs/switch/switch.css.cjs +1 -1
- package/dist/inputs/switch/switch.css.cjs.map +1 -1
- package/dist/inputs/switch/switch.css.js +1 -1
- package/dist/inputs/switch/switch.css.js.map +1 -1
- package/dist/keyboard-key.cjs +9 -0
- package/dist/keyboard-key.cjs.map +1 -0
- package/dist/keyboard-key.js +36 -0
- package/dist/keyboard-key.js.map +1 -0
- package/dist/layout/navbar/navbar.css.cjs +1 -1
- package/dist/layout/navbar/navbar.css.cjs.map +1 -1
- package/dist/layout/navbar/navbar.css.js +1 -1
- package/dist/layout/navbar/navbar.css.js.map +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js +2 -1
- package/dist/menu.js.map +1 -1
- package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
- package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
- package/dist/overlay/command-palette/command-palette.css.js +1 -1
- package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
- package/dist/overlay/command-palette/command-palette.d.ts +1 -0
- package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
- package/dist/progress.cjs +14 -6
- package/dist/progress.cjs.map +1 -1
- package/dist/progress.js +19 -7
- package/dist/progress.js.map +1 -1
- package/dist/qr-code.cjs +15 -0
- package/dist/qr-code.cjs.map +1 -0
- package/dist/qr-code.js +70 -0
- package/dist/qr-code.js.map +1 -0
- package/dist/qr-scanner.cjs +46 -0
- package/dist/qr-scanner.cjs.map +1 -0
- package/dist/qr-scanner.js +129 -0
- package/dist/qr-scanner.js.map +1 -0
- package/dist/refine.cjs +327 -166
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +355 -194
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +298 -137
- package/dist/refine.js.map +1 -1
- package/dist/tabs.cjs +2 -2
- package/dist/tabs.cjs.map +1 -1
- package/dist/tabs.js +37 -34
- package/dist/tabs.js.map +1 -1
- package/dist/types/elements.d.ts +9 -0
- package/package.json +35 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step.css.js","names":[],"sources":["../../../src/content/stepper/step.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --step-indicator-size: var(--size-8);\n --step-font-size: var(--text-sm);\n --step-gap: var(--size-2);\n display: flex;\n flex: 1 1 0%;\n min-width: 0;\n }\n\n .step {\n position: relative;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n width: 100%;\n list-style: none;\n }\n\n /* Horizontal (default) layout centers the indicator above the label in each equal-width\n column (see `.control`/`.content` below) so the indicator sits at a predictable, constant\n horizontal position — the midpoint of its own step — regardless of label length. The full\n line between two indicators is drawn as *two* halves — this step's own `.connector-leading`\n (its own left edge to its own indicator) and `.connector-trailing` (its own indicator to its\n own right edge) — each confined entirely inside this step's own box. Reaching a single\n connector backward into the previous step's box (an earlier attempt) doesn't work: `ore-step`\n is its own custom element/shadow root, so a later sibling's positioned content always paints\n in front of an earlier sibling's regardless of internal stacking, and `.control`'s own hover\n background only covers its own box — so the part of the line sitting outside it looked like\n a stray line poking out next to the hover highlight instead of being part of it. */\n .connector {\n position: absolute;\n top: calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: calc(50% - var(--step-indicator-size) / 2);\n height: var(--stepper-connector-size, 2px);\n background: var(--stepper-connector-color, var(--color-contrast-200));\n border-radius: var(--rounded-full);\n transform: translateY(-50%);\n transition: background var(--transition-fast);\n }\n\n .connector-leading {\n left: 0;\n }\n\n .connector-trailing {\n right: 0;\n }\n\n /* No preceding/following step to connect to. */\n :host(:first-of-type) .connector-leading {\n display: none;\n }\n\n :host(:last-of-type) .connector-trailing {\n display: none;\n }\n\n .control {\n all: unset;\n\n /* Declared after `all: unset` (which resets `position` back to `static`), not before it.\n Puts `.control` in the same paint order as `.connector` (also positioned) instead of\n `.connector` — being absolutely positioned — automatically painting above all of this\n *static*, normal-flow content regardless of DOM order. `.control` comes after\n `.connector` in the markup, so with both positioned it (and the opaque indicator inside\n it) now correctly paints over the connector line instead of the line cutting across\n every indicator. */\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--step-gap);\n align-items: center;\n width: 100%;\n min-width: 0;\n padding: var(--size-1);\n font-family: inherit;\n cursor: default;\n border-radius: var(--rounded-lg);\n }\n\n button.control {\n min-height: var(--_touch-target, auto);\n cursor: pointer;\n transition: background var(--transition-fast);\n }\n\n button.control:focus-visible {\n outline: var(--border-2) solid var(--_theme-base, var(--color-contrast-500));\n outline-offset: var(--border-2);\n }\n\n button.control[aria-disabled='true'] {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .indicator {\n /* Without this, the `border` below adds on top of `width`/`height` instead of being\n included in them, rendering the indicator ~2 * border-width larger per axis than\n `--step-indicator-size` — every connector position calc using that variable to line up\n with the indicator's true center/edge (especially the vertical connector's horizontal\n `left`, which has no flexbox centering to fall back on) would then be off by that much. */\n box-sizing: border-box;\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--step-indicator-size);\n height: var(--step-indicator-size);\n font-size: var(--step-font-size);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n background: var(--color-contrast-100);\n border: var(--border-2) solid var(--color-contrast-200);\n border-radius: var(--rounded-full);\n transition:\n background var(--transition-fast),\n color var(--transition-fast),\n border-color var(--transition-fast);\n }\n\n .icon-slot[hidden] {\n display: none;\n }\n\n .number {\n line-height: 1;\n }\n\n .content {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n text-align: center;\n }\n\n .label {\n display: flex;\n gap: var(--size-1);\n align-items: baseline;\n justify-content: center;\n min-width: 0;\n font-size: var(--step-font-size);\n font-weight: var(--font-medium);\n color: var(--color-contrast-700);\n }\n\n .label-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .optional-hint {\n flex: 0 0 auto;\n font-size: var(--text-xs);\n font-weight: var(--font-normal);\n color: var(--color-contrast-400);\n }\n\n .description {\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n }\n\n .description[hidden] {\n display: none;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n white-space: nowrap;\n border-width: 0;\n clip-path: inset(50%);\n }\n}\n\n@layer refine.states {\n :host([current]) .indicator {\n color: var(--_theme-contrast, var(--color-canvas));\n background: var(--_theme-base, var(--color-contrast-800));\n border-color: var(--_theme-base, var(--color-contrast-800));\n }\n\n :host([current]) .label {\n font-weight: var(--font-semibold);\n color: var(--color-contrast-900);\n }\n\n :host([completed]) .indicator {\n color: var(--_theme-contrast, var(--color-canvas));\n background: var(--_theme-focus, var(--color-contrast-600));\n border-color: var(--_theme-focus, var(--color-contrast-600));\n }\n\n /* A completed step colors both the segment leading into it and the one trailing out of it\n (progress has fully passed through); the current step only colors the leading segment\n (progress has arrived, but not yet moved past it into the next step). */\n :host([completed]) .connector,\n :host([current]) .connector-leading {\n background: var(--_theme-focus, var(--color-contrast-400));\n }\n\n :host([error]) .indicator {\n color: var(--color-canvas);\n background: var(--color-error);\n border-color: var(--color-error);\n }\n\n :host([error]) .label {\n color: var(--color-error);\n }\n\n :host([disabled]) .label,\n :host([disabled]) .description {\n color: var(--color-contrast-400);\n }\n\n :host([disabled]) .indicator {\n opacity: 0.6;\n }\n}\n\n@layer refine.sizes {\n :host([size='sm']) {\n --step-indicator-size: var(--size-6);\n --step-font-size: var(--text-xs);\n --step-gap: var(--size-1-5);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --step-indicator-size: var(--size-8);\n --step-font-size: var(--text-sm);\n --step-gap: var(--size-2);\n }\n\n :host([size='lg']) {\n --step-indicator-size: var(--size-10);\n --step-font-size: var(--text-base);\n --step-gap: var(--size-2-5);\n }\n\n @media (pointer: coarse) {\n :host(:not([size])),\n :host([size='sm']),\n :host([size='md']) {\n --step-indicator-size: var(--size-9);\n --step-font-size: var(--text-sm);\n }\n }\n}\n\n@layer refine.orientation {\n /* Vertical (mobile-friendly) layout: back to the inline icon-beside-label arrangement (more\n compact for narrow/mobile widths), with `padding-block-start` reserving room for a\n top-to-bottom connector into this step's own indicator instead of the horizontal\n center-to-center line above. */\n :host([orientation='vertical']) {\n flex: 0 0 auto;\n width: 100%;\n }\n\n :host([orientation='vertical']) .step {\n align-items: flex-start;\n padding-block-start: var(--stepper-gap, var(--size-4));\n }\n\n :host([orientation='vertical']:first-of-type) .step {\n padding-block-start: 0;\n }\n\n :host([orientation='vertical']) .control {\n flex-direction: row;\n align-items: flex-start;\n }\n\n :host([orientation='vertical']) .content {\n align-items: flex-start;\n text-align: left;\n }\n\n :host([orientation='vertical']) .label {\n justify-content: flex-start;\n }\n\n /* Same two-halves idea as horizontal, rotated: `.connector-leading` runs from this step's own\n top edge down into its indicator (through the `padding-block-start` gap reserved above).\n `.connector-trailing` runs from the *bottom* of this step's indicator down to this step's\n own bottom edge — using `top`+`bottom` (no fixed `height`) so it stretches to whatever this\n step's content actually needs, instead of a fixed length that only reached as far as the\n padding gap. A step with a longer description is taller, and its trailing segment grows\n with it — the next step's leading segment then only has to bridge the fixed padding gap,\n so the two halves always meet exactly at the boundary between the two steps regardless of\n how much content either one has. */\n :host([orientation='vertical']) .connector-leading {\n top: 0;\n left: calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: var(--stepper-connector-size, 2px);\n height: calc(var(--stepper-gap, var(--size-4)) + var(--size-1));\n transform: translateX(-50%);\n }\n\n :host([orientation='vertical']) .connector-trailing {\n inset: calc(var(--stepper-gap, var(--size-4)) + var(--size-1) + var(--step-indicator-size)) auto 0\n calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: var(--stepper-connector-size, 2px);\n height: auto;\n transform: translateX(-50%);\n }\n\n /* The first step's `padding-block-start` is reset to 0 above (no incoming line to make room\n for) — `.connector-trailing`'s `top` has to drop the same gap term here, or it starts\n lower than the indicator's true bottom edge and its `bottom: 0` counterpart can compute a\n negative (clamped to 0) height, hiding the segment entirely. */\n :host([orientation='vertical']:first-of-type) .connector-trailing {\n top: calc(var(--size-1) + var(--step-indicator-size));\n }\n}\n\n@media (forced-colors: active) {\n .indicator {\n border: 1px solid ButtonText;\n }\n\n :host([current]) .indicator,\n :host([completed]) .indicator {\n border: 1px solid Highlight;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"step.css.js","names":[],"sources":["../../../src/content/stepper/step.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --step-indicator-size: var(--size-8);\n --step-font-size: var(--text-sm);\n --step-gap: var(--size-2);\n display: flex;\n flex: 1 1 0%;\n min-width: 0;\n }\n\n .step {\n position: relative;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n width: 100%;\n list-style: none;\n }\n\n /* Horizontal (default) layout centers the indicator above the label in each equal-width\n column (see `.control`/`.content` below) so the indicator sits at a predictable, constant\n horizontal position — the midpoint of its own step — regardless of label length. The full\n line between two indicators is drawn as *two* halves — this step's own `.connector-leading`\n (its own left edge to its own indicator) and `.connector-trailing` (its own indicator to its\n own right edge) — each confined entirely inside this step's own box. Reaching a single\n connector backward into the previous step's box (an earlier attempt) doesn't work: `ore-step`\n is its own custom element/shadow root, so a later sibling's positioned content always paints\n in front of an earlier sibling's regardless of internal stacking, and `.control`'s own hover\n background only covers its own box — so the part of the line sitting outside it looked like\n a stray line poking out next to the hover highlight instead of being part of it. */\n .connector {\n position: absolute;\n top: calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: calc(50% - var(--step-indicator-size) / 2);\n height: var(--stepper-connector-size, 2px);\n background: var(--stepper-connector-color, var(--color-contrast-200));\n border-radius: var(--rounded-full);\n transform: translateY(-50%);\n transition: background var(--transition-fast);\n }\n\n .connector-leading {\n left: 0;\n }\n\n .connector-trailing {\n right: 0;\n }\n\n /* No preceding/following step to connect to. */\n :host(:first-of-type) .connector-leading {\n display: none;\n }\n\n :host(:last-of-type) .connector-trailing {\n display: none;\n }\n\n .control {\n all: unset;\n\n /* Declared after `all: unset` (which resets `position` back to `static`), not before it.\n Puts `.control` in the same paint order as `.connector` (also positioned) instead of\n `.connector` — being absolutely positioned — automatically painting above all of this\n *static*, normal-flow content regardless of DOM order. `.control` comes after\n `.connector` in the markup, so with both positioned it (and the opaque indicator inside\n it) now correctly paints over the connector line instead of the line cutting across\n every indicator. */\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--step-gap);\n align-items: center;\n width: 100%;\n min-width: 0;\n padding: var(--size-1);\n font-family: inherit;\n cursor: default;\n border-radius: var(--rounded-lg);\n }\n\n button.control {\n min-height: var(--_touch-target, auto);\n cursor: pointer;\n transition: background var(--transition-fast);\n }\n\n button.control:focus-visible {\n outline: var(--border-2) solid var(--_theme-base, var(--color-contrast-500));\n outline-offset: var(--border-2);\n }\n\n button.control[aria-disabled='true'] {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .indicator {\n /* Without this, the `border` below adds on top of `width`/`height` instead of being\n included in them, rendering the indicator ~2 * border-width larger per axis than\n `--step-indicator-size` — every connector position calc using that variable to line up\n with the indicator's true center/edge (especially the vertical connector's horizontal\n `left`, which has no flexbox centering to fall back on) would then be off by that much. */\n box-sizing: border-box;\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--step-indicator-size);\n height: var(--step-indicator-size);\n font-size: var(--step-font-size);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n background: var(--color-contrast-100);\n border: var(--border-2) solid var(--color-contrast-200);\n border-radius: var(--rounded-full);\n transition:\n background var(--transition-fast),\n color var(--transition-fast),\n border-color var(--transition-fast);\n }\n\n .icon-slot[hidden] {\n display: none;\n }\n\n .number {\n line-height: 1;\n }\n\n .content {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n max-width: 100%;\n text-align: center;\n }\n\n .label {\n display: flex;\n gap: var(--size-1);\n align-items: baseline;\n justify-content: center;\n min-width: 0;\n max-width: 100%;\n font-size: var(--step-font-size);\n font-weight: var(--font-medium);\n color: var(--color-contrast-700);\n }\n\n .label-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .optional-hint {\n flex: 0 0 auto;\n font-size: var(--text-xs);\n font-weight: var(--font-normal);\n color: var(--color-contrast-400);\n }\n\n .description {\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n }\n\n .description[hidden] {\n display: none;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n white-space: nowrap;\n border-width: 0;\n clip-path: inset(50%);\n }\n}\n\n@layer refine.states {\n :host([current]) .indicator {\n color: var(--_theme-contrast, var(--color-canvas));\n background: var(--_theme-base, var(--color-contrast-800));\n border-color: var(--_theme-base, var(--color-contrast-800));\n }\n\n :host([current]) .label {\n font-weight: var(--font-semibold);\n color: var(--color-contrast-900);\n }\n\n :host([completed]) .indicator {\n color: var(--_theme-contrast, var(--color-canvas));\n background: var(--_theme-focus, var(--color-contrast-600));\n border-color: var(--_theme-focus, var(--color-contrast-600));\n }\n\n /* A completed step colors both the segment leading into it and the one trailing out of it\n (progress has fully passed through); the current step only colors the leading segment\n (progress has arrived, but not yet moved past it into the next step). */\n :host([completed]) .connector,\n :host([current]) .connector-leading {\n background: var(--_theme-focus, var(--color-contrast-400));\n }\n\n :host([error]) .indicator {\n color: var(--color-canvas);\n background: var(--color-error);\n border-color: var(--color-error);\n }\n\n :host([error]) .label {\n color: var(--color-error);\n }\n\n :host([disabled]) .label,\n :host([disabled]) .description {\n color: var(--color-contrast-400);\n }\n\n :host([disabled]) .indicator {\n opacity: 0.6;\n }\n}\n\n@layer refine.sizes {\n :host([size='sm']) {\n --step-indicator-size: var(--size-6);\n --step-font-size: var(--text-xs);\n --step-gap: var(--size-1-5);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --step-indicator-size: var(--size-8);\n --step-font-size: var(--text-sm);\n --step-gap: var(--size-2);\n }\n\n :host([size='lg']) {\n --step-indicator-size: var(--size-10);\n --step-font-size: var(--text-base);\n --step-gap: var(--size-2-5);\n }\n\n @media (pointer: coarse) {\n :host(:not([size])),\n :host([size='sm']),\n :host([size='md']) {\n --step-indicator-size: var(--size-9);\n --step-font-size: var(--text-sm);\n }\n }\n}\n\n@layer refine.orientation {\n /* Vertical (mobile-friendly) layout: back to the inline icon-beside-label arrangement (more\n compact for narrow/mobile widths), with `padding-block-start` reserving room for a\n top-to-bottom connector into this step's own indicator instead of the horizontal\n center-to-center line above. */\n :host([orientation='vertical']) {\n flex: 0 0 auto;\n width: 100%;\n }\n\n :host([orientation='vertical']) .step {\n align-items: flex-start;\n padding-block-start: var(--stepper-gap, var(--size-4));\n }\n\n :host([orientation='vertical']:first-of-type) .step {\n padding-block-start: 0;\n }\n\n :host([orientation='vertical']) .control {\n flex-direction: row;\n align-items: flex-start;\n }\n\n :host([orientation='vertical']) .content {\n align-items: flex-start;\n text-align: left;\n }\n\n :host([orientation='vertical']) .label {\n justify-content: flex-start;\n }\n\n /* Same two-halves idea as horizontal, rotated: `.connector-leading` runs from this step's own\n top edge down into its indicator (through the `padding-block-start` gap reserved above).\n `.connector-trailing` runs from the *bottom* of this step's indicator down to this step's\n own bottom edge — using `top`+`bottom` (no fixed `height`) so it stretches to whatever this\n step's content actually needs, instead of a fixed length that only reached as far as the\n padding gap. A step with a longer description is taller, and its trailing segment grows\n with it — the next step's leading segment then only has to bridge the fixed padding gap,\n so the two halves always meet exactly at the boundary between the two steps regardless of\n how much content either one has. */\n :host([orientation='vertical']) .connector-leading {\n top: 0;\n left: calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: var(--stepper-connector-size, 2px);\n height: calc(var(--stepper-gap, var(--size-4)) + var(--size-1));\n transform: translateX(-50%);\n }\n\n :host([orientation='vertical']) .connector-trailing {\n inset: calc(var(--stepper-gap, var(--size-4)) + var(--size-1) + var(--step-indicator-size)) auto 0\n calc(var(--size-1) + var(--step-indicator-size) / 2);\n width: var(--stepper-connector-size, 2px);\n height: auto;\n transform: translateX(-50%);\n }\n\n /* The first step's `padding-block-start` is reset to 0 above (no incoming line to make room\n for) — `.connector-trailing`'s `top` has to drop the same gap term here, or it starts\n lower than the indicator's true bottom edge and its `bottom: 0` counterpart can compute a\n negative (clamped to 0) height, hiding the segment entirely. */\n :host([orientation='vertical']:first-of-type) .connector-trailing {\n top: calc(var(--size-1) + var(--step-indicator-size));\n }\n}\n\n@media (forced-colors: active) {\n .indicator {\n border: 1px solid ButtonText;\n }\n\n :host([current]) .indicator,\n :host([completed]) .indicator {\n border: 1px solid Highlight;\n }\n}\n"],"mappings":""}
|
package/dist/counter.cjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/states.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./core/spinner.cjs"),i=require("./shared/prop-bundles.cjs"),a=require("./inputs/counter/counter.css.cjs");let o=require("@vielzeug/ore"),s=require("@vielzeug/ripple");var c=400,l=120,u=`ore-counter`;(0,o.define)(u,{props:{...i.themableBundle,...i.sizableBundle,...i.disablableBundle,hint:o.prop.string(),label:o.prop.string(),"large-step":o.prop.json(void 0),max:o.prop.json(void 0),min:o.prop.number(0),"quick-steps":o.prop.bool(!1),readonly:o.prop.bool(!1),step:o.prop.number(1),value:o.prop.number(0)},setup(e){let t=(0,o.getHost)(),n=(0,o.useEmit)(),i=(0,o.createId)(`counter-label`),a=(0,o.createId)(`counter-hint`),c=(0,s.signal)(Number(e.value.value)||0);(0,s.watch)(e.value,e=>{let t=Number(e);Number.isFinite(t)&&t!==c.value&&(c.value=t)});let l=(0,s.computed)(()=>!!e.disabled.value),u=(0,s.computed)(()=>!!e.readonly.value),d=(0,s.computed)(()=>!l.value&&!u.value),f=(0,s.computed)(()=>!!e.hint.value),p=(0,s.signal)(!1),m=null,h=r.createSpinnerControl({commit:e=>{if(e==null)return;let r=e-c.value;r!==0&&(c.value=e,t.setAttribute(`value`,String(e)),n(`change`,{delta:r,value:e}),m&&clearTimeout(m),p.value=!1,p.value=!0,m=setTimeout(()=>{p.value=!1,m=null},200))},disabled:l,largeStep:e[`large-step`],max:e.max,min:e.min,parse:()=>c.value,readonly:u,step:e.step}),g=()=>Number(e.step.value)||1,_=()=>Number(e[`large-step`].value)||g()*10,v=(0,s.computed)(()=>!!e[`quick-steps`].value),y=null,b=null,x=!1,S=()=>{y&&clearTimeout(y),b&&clearInterval(b),y=null,b=null},C=(e,t)=>{d.value&&t.button===0&&(S(),x=!1,y=setTimeout(()=>{x=!0,h.incrementBy(e(),t),b=setInterval(()=>{let n=e();if(n>0&&h.atMax()||n<0&&h.atMin()){S();return}h.incrementBy(n,t)},120)},400))},w=(e,t)=>{if(x){x=!1;return}h.incrementBy(e(),t)},T=e=>()=>e*g(),E=e=>()=>e*_(),D=e=>()=>`${e>0?`+`:`−`}${_()}`;(0,o.onCleanup)(()=>{S(),m&&clearTimeout(m)}),(0,o.bind)({attr:{"data-bump":()=>p.value?``:null,size:e.size}});let O=(0,s.computed)(()=>f.value?a:null);return o.html`
|
|
2
|
+
<div class="counter" part="counter" role="group" aria-labelledby="${i}">
|
|
3
|
+
<div class="header" part="header">
|
|
4
|
+
<slot name="icon"></slot>
|
|
5
|
+
<span class="label" part="label" id="${i}">${()=>e.label.value??``}</span>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="controls" part="controls" @keydown="${e=>h.handleKeydown(e)}">
|
|
8
|
+
<button
|
|
9
|
+
class="btn btn-large"
|
|
10
|
+
part="decrement-large-btn"
|
|
11
|
+
type="button"
|
|
12
|
+
tabindex="-1"
|
|
13
|
+
aria-label="${()=>`Decrease ${e.label.value??``} by ${_()}`.trim()}"
|
|
14
|
+
?hidden="${()=>u.value||!v.value}"
|
|
15
|
+
?disabled="${()=>!d.value||h.atMin()}"
|
|
16
|
+
@pointerdown="${e=>C(E(-1),e)}"
|
|
17
|
+
@pointerup="${S}"
|
|
18
|
+
@pointercancel="${S}"
|
|
19
|
+
@pointerleave="${S}"
|
|
20
|
+
@click="${e=>w(E(-1),e)}">
|
|
21
|
+
${D(-1)}
|
|
22
|
+
</button>
|
|
23
|
+
<button
|
|
24
|
+
class="btn"
|
|
25
|
+
part="decrement-btn"
|
|
26
|
+
type="button"
|
|
27
|
+
tabindex="-1"
|
|
28
|
+
aria-label="${()=>`Decrease ${e.label.value??``}`.trim()}"
|
|
29
|
+
?hidden="${u}"
|
|
30
|
+
?disabled="${()=>!d.value||h.atMin()}"
|
|
31
|
+
@pointerdown="${e=>C(T(-1),e)}"
|
|
32
|
+
@pointerup="${S}"
|
|
33
|
+
@pointercancel="${S}"
|
|
34
|
+
@pointerleave="${S}"
|
|
35
|
+
@click="${e=>w(T(-1),e)}">
|
|
36
|
+
<ore-icon name="minus" size="var(--_icon-size)" stroke-width="2.5" aria-hidden="true"></ore-icon>
|
|
37
|
+
</button>
|
|
38
|
+
<output
|
|
39
|
+
class="value"
|
|
40
|
+
part="value"
|
|
41
|
+
role="spinbutton"
|
|
42
|
+
aria-live="polite"
|
|
43
|
+
aria-labelledby="${i}"
|
|
44
|
+
aria-describedby="${O}"
|
|
45
|
+
aria-valuenow="${()=>String(c.value)}"
|
|
46
|
+
aria-valuemin="${()=>e.min.value==null?null:String(e.min.value)}"
|
|
47
|
+
aria-valuemax="${()=>e.max.value==null?null:String(e.max.value)}"
|
|
48
|
+
aria-readonly="${()=>u.value?`true`:null}"
|
|
49
|
+
aria-disabled="${()=>l.value?`true`:null}"
|
|
50
|
+
tabindex="${()=>l.value?`-1`:`0`}">
|
|
51
|
+
${()=>String(c.value)}
|
|
52
|
+
</output>
|
|
53
|
+
<button
|
|
54
|
+
class="btn"
|
|
55
|
+
part="increment-btn"
|
|
56
|
+
type="button"
|
|
57
|
+
tabindex="-1"
|
|
58
|
+
aria-label="${()=>`Increase ${e.label.value??``}`.trim()}"
|
|
59
|
+
?hidden="${u}"
|
|
60
|
+
?disabled="${()=>!d.value||h.atMax()}"
|
|
61
|
+
@pointerdown="${e=>C(T(1),e)}"
|
|
62
|
+
@pointerup="${S}"
|
|
63
|
+
@pointercancel="${S}"
|
|
64
|
+
@pointerleave="${S}"
|
|
65
|
+
@click="${e=>w(T(1),e)}">
|
|
66
|
+
<ore-icon name="plus" size="var(--_icon-size)" stroke-width="2.5" aria-hidden="true"></ore-icon>
|
|
67
|
+
</button>
|
|
68
|
+
<button
|
|
69
|
+
class="btn btn-large"
|
|
70
|
+
part="increment-large-btn"
|
|
71
|
+
type="button"
|
|
72
|
+
tabindex="-1"
|
|
73
|
+
aria-label="${()=>`Increase ${e.label.value??``} by ${_()}`.trim()}"
|
|
74
|
+
?hidden="${()=>u.value||!v.value}"
|
|
75
|
+
?disabled="${()=>!d.value||h.atMax()}"
|
|
76
|
+
@pointerdown="${e=>C(E(1),e)}"
|
|
77
|
+
@pointerup="${S}"
|
|
78
|
+
@pointercancel="${S}"
|
|
79
|
+
@pointerleave="${S}"
|
|
80
|
+
@click="${e=>w(E(1),e)}">
|
|
81
|
+
${D(1)}
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
<slot name="hint">
|
|
85
|
+
<span class="hint" part="hint" id="${a}" ?hidden="${()=>!f.value}">
|
|
86
|
+
${()=>e.hint.value??``}
|
|
87
|
+
</span>
|
|
88
|
+
</slot>
|
|
89
|
+
</div>
|
|
90
|
+
`},shadow:{delegatesFocus:!0},styles:[n.colorThemeMixin,t.disabledStateMixin,e.coarsePointerMixin,e.reducedMotionMixin,a.default]}),exports.COUNTER_HOLD_DELAY_MS=c,exports.COUNTER_HOLD_REPEAT_MS=l,exports.COUNTER_TAG=u;
|
|
91
|
+
//# sourceMappingURL=counter.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.cjs","names":[],"sources":["../src/inputs/counter/counter.ts"],"sourcesContent":["import { bind, createId, define, getHost, html, onCleanup, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { createSpinnerControl } from '../../core';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport '../../content/icon/icon';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, disabledStateMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './counter.css?inline';\n\nexport type OreCounterChangeDetail = {\n /** Difference between the new and the previous value */\n delta: number;\n /** New value after clamping */\n value: number;\n};\n\nexport type OreCounterEvents = {\n change: OreCounterChangeDetail;\n};\n\n/** Counter props */\nexport type OreCounterProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** One-line timing or usage hint rendered under the controls */\n hint?: string;\n /** Visible label; also names the control for assistive technology */\n label?: string;\n /** Step for Page Up/Down (default: 10 × step) */\n 'large-step'?: number;\n /** Maximum allowed value */\n max?: number;\n /** Minimum allowed value (default: 0) */\n min?: number;\n /** Render an outer pair of −/+ buttons that move by `large-step` */\n 'quick-steps'?: boolean;\n /** Show the value without controls */\n readonly?: boolean;\n /** Component size */\n size?: ComponentSize;\n /** Increment/decrement step (default: 1) */\n step?: number;\n /** Current value */\n value?: number;\n};\n\n/** Hold delay before auto-repeat starts, then the repeat interval. */\nexport const COUNTER_HOLD_DELAY_MS = 400;\nexport const COUNTER_HOLD_REPEAT_MS = 120;\n\n/**\n * A large-target tally control for counting things at a glance: `−` / value / `+` with an\n * optional icon, label and hint. Designed for touch and arm's-length use (tabletop trackers,\n * inventories, scoreboards) rather than typed form entry — use `ore-number-input` for that.\n *\n * Holding any button auto-repeats. The value is announced through a live region and is\n * keyboard-operable as a spinbutton (Arrow keys, Home/End, Page Up/Down). Set `quick-steps` to add an\n * outer pair of buttons that move by `large-step`, for values that change in chunks (damage, scores).\n *\n * @element ore-counter\n *\n * @attr {number} value - Current value (default: 0)\n * @attr {number} min - Minimum value (default: 0)\n * @attr {number} max - Maximum value\n * @attr {number} step - Increment/decrement step (default: 1)\n * @attr {number} large-step - Step for Page Up/Down and the quick-step buttons (default: 10 × step)\n * @attr {boolean} quick-steps - Adds an outer −/+ pair that moves by `large-step`\n * @attr {boolean} disabled - Disables the control\n * @attr {boolean} readonly - Shows the value without the −/+ buttons\n * @attr {string} label - Visible label and accessible name\n * @attr {string} hint - One-line hint under the controls\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @fires change - Fired after every accepted change. detail: { value: number, delta: number }\n *\n * @slot icon - Leading icon or token artwork shown before the label\n * @slot hint - Custom hint content (replaces the `hint` attribute)\n *\n * @cssprop --counter-value-size - Font size of the value\n * @cssprop --counter-button-size - Width/height of the −/+ buttons\n * @cssprop --counter-gap - Gap between the buttons and the value\n * @cssprop --counter-bg - Background of the control\n * @cssprop --counter-border-color - Border color of the control\n * @cssprop --counter-radius - Border radius of the control\n * @cssprop --counter-icon-size - Size of the slotted icon\n *\n * @part counter - Root container.\n * @part header - Icon and label row.\n * @part label - Label element.\n * @part controls - Buttons and value row.\n * @part decrement-large-btn - Quick-step decrement button (`quick-steps` only).\n * @part decrement-btn - Decrement button.\n * @part value - Value output.\n * @part increment-btn - Increment button.\n * @part increment-large-btn - Quick-step increment button (`quick-steps` only).\n * @part hint - Hint element.\n *\n * @example\n * ```html\n * <ore-counter label=\"Stamina\" value=\"3\" hint=\"Pay for actions\">\n * <ore-icon slot=\"icon\" name=\"zap\"></ore-icon>\n * </ore-counter>\n * <ore-counter label=\"Score\" value=\"10\" min=\"0\" max=\"99\" size=\"lg\" color=\"primary\"></ore-counter>\n * <ore-counter label=\"Damage\" value=\"12\" large-step=\"5\" quick-steps></ore-counter>\n * ```\n */\nexport const COUNTER_TAG = 'ore-counter' as const;\ndefine<OreCounterProps>(COUNTER_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n hint: prop.string(),\n label: prop.string(),\n 'large-step': prop.json(undefined as number | undefined),\n max: prop.json(undefined as number | undefined),\n min: prop.number(0),\n 'quick-steps': prop.bool(false),\n readonly: prop.bool(false),\n step: prop.number(1),\n value: prop.number(0),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCounterEvents>();\n const labelId = createId('counter-label');\n const hintId = createId('counter-hint');\n\n const current = signal(Number(props.value.value) || 0);\n\n watch(props.value, (next) => {\n const parsed = Number(next);\n\n if (Number.isFinite(parsed) && parsed !== current.value) current.value = parsed;\n });\n\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const isReadonly = computed(() => Boolean(props.readonly.value));\n const isInteractive = computed(() => !isDisabled.value && !isReadonly.value);\n const hasHint = computed(() => Boolean(props.hint.value));\n\n // Toggled briefly on every change so the CSS bump animation restarts.\n const bumped = signal(false);\n let bumpTimer: ReturnType<typeof setTimeout> | null = null;\n\n const commit = (next: number | null): void => {\n if (next == null) return;\n\n const delta = next - current.value;\n\n if (delta === 0) return;\n\n current.value = next;\n el.setAttribute('value', String(next));\n emit('change', { delta, value: next });\n\n if (bumpTimer) clearTimeout(bumpTimer);\n bumped.value = false;\n bumped.value = true;\n bumpTimer = setTimeout(() => {\n bumped.value = false;\n bumpTimer = null;\n }, 200);\n };\n\n const spinner = createSpinnerControl({\n commit,\n disabled: isDisabled,\n largeStep: props['large-step'],\n max: props.max,\n min: props.min,\n parse: () => current.value,\n readonly: isReadonly,\n step: props.step,\n });\n\n const stepSize = (): number => Number(props.step.value) || 1;\n const largeStepSize = (): number => Number(props['large-step'].value) || stepSize() * 10;\n const hasQuickSteps = computed(() => Boolean(props['quick-steps'].value));\n\n // ── Press-and-hold auto-repeat ──────────────────────────────────────────\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let repeatTimer: ReturnType<typeof setInterval> | null = null;\n let repeated = false;\n\n const stopHold = (): void => {\n if (holdTimer) clearTimeout(holdTimer);\n if (repeatTimer) clearInterval(repeatTimer);\n holdTimer = null;\n repeatTimer = null;\n };\n\n const startHold = (amount: () => number, e: PointerEvent): void => {\n if (!isInteractive.value || e.button !== 0) return;\n\n stopHold();\n repeated = false;\n holdTimer = setTimeout(() => {\n repeated = true;\n spinner.incrementBy(amount(), e);\n repeatTimer = setInterval(() => {\n const direction = amount();\n\n if ((direction > 0 && spinner.atMax()) || (direction < 0 && spinner.atMin())) {\n stopHold();\n\n return;\n }\n\n spinner.incrementBy(direction, e);\n }, COUNTER_HOLD_REPEAT_MS);\n }, COUNTER_HOLD_DELAY_MS);\n };\n\n // The click that ends a long-press must not add one more step on top of the repeats.\n const handleClick = (amount: () => number, e: Event): void => {\n if (repeated) {\n repeated = false;\n\n return;\n }\n\n spinner.incrementBy(amount(), e);\n };\n\n const small = (direction: 1 | -1) => (): number => direction * stepSize();\n const large = (direction: 1 | -1) => (): number => direction * largeStepSize();\n const quickLabel = (direction: 1 | -1) => (): string => `${direction > 0 ? '+' : '−'}${largeStepSize()}`;\n\n onCleanup(() => {\n stopHold();\n if (bumpTimer) clearTimeout(bumpTimer);\n });\n\n bind({\n attr: {\n 'data-bump': () => (bumped.value ? '' : null),\n size: props.size,\n },\n });\n\n const describedBy = computed(() => (hasHint.value ? hintId : null));\n\n return html`\n <div class=\"counter\" part=\"counter\" role=\"group\" aria-labelledby=\"${labelId}\">\n <div class=\"header\" part=\"header\">\n <slot name=\"icon\"></slot>\n <span class=\"label\" part=\"label\" id=\"${labelId}\">${() => props.label.value ?? ''}</span>\n </div>\n <div class=\"controls\" part=\"controls\" @keydown=\"${(e: KeyboardEvent) => spinner.handleKeydown(e)}\">\n <button\n class=\"btn btn-large\"\n part=\"decrement-large-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Decrease ${props.label.value ?? ''} by ${largeStepSize()}`.trim()}\"\n ?hidden=\"${() => isReadonly.value || !hasQuickSteps.value}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMin()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(large(-1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(large(-1), e)}\">\n ${quickLabel(-1)}\n </button>\n <button\n class=\"btn\"\n part=\"decrement-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Decrease ${props.label.value ?? ''}`.trim()}\"\n ?hidden=\"${isReadonly}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMin()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(small(-1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(small(-1), e)}\">\n <ore-icon name=\"minus\" size=\"var(--_icon-size)\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <output\n class=\"value\"\n part=\"value\"\n role=\"spinbutton\"\n aria-live=\"polite\"\n aria-labelledby=\"${labelId}\"\n aria-describedby=\"${describedBy}\"\n aria-valuenow=\"${() => String(current.value)}\"\n aria-valuemin=\"${() => (props.min.value != null ? String(props.min.value) : null)}\"\n aria-valuemax=\"${() => (props.max.value != null ? String(props.max.value) : null)}\"\n aria-readonly=\"${() => (isReadonly.value ? 'true' : null)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n tabindex=\"${() => (isDisabled.value ? '-1' : '0')}\">\n ${() => String(current.value)}\n </output>\n <button\n class=\"btn\"\n part=\"increment-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Increase ${props.label.value ?? ''}`.trim()}\"\n ?hidden=\"${isReadonly}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMax()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(small(1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(small(1), e)}\">\n <ore-icon name=\"plus\" size=\"var(--_icon-size)\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <button\n class=\"btn btn-large\"\n part=\"increment-large-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Increase ${props.label.value ?? ''} by ${largeStepSize()}`.trim()}\"\n ?hidden=\"${() => isReadonly.value || !hasQuickSteps.value}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMax()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(large(1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(large(1), e)}\">\n ${quickLabel(1)}\n </button>\n </div>\n <slot name=\"hint\">\n <span class=\"hint\" part=\"hint\" id=\"${hintId}\" ?hidden=\"${() => !hasHint.value}\">\n ${() => props.hint.value ?? ''}\n </span>\n </slot>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, disabledStateMixin, coarsePointerMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/counter.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { coarsePointerMixin as e, reducedMotionMixin as t } from "./styles/mixins/accessibility.css.js";
|
|
2
|
+
import { disabledStateMixin as n } from "./styles/mixins/states.css.js";
|
|
3
|
+
import { colorThemeMixin as r } from "./styles/mixins/theme.css.js";
|
|
4
|
+
import { createSpinnerControl as i } from "./core/spinner.js";
|
|
5
|
+
import { disablableBundle as a, sizableBundle as o, themableBundle as s } from "./shared/prop-bundles.js";
|
|
6
|
+
import c from "./inputs/counter/counter.css.js";
|
|
7
|
+
import { bind as l, createId as u, define as d, getHost as f, html as p, onCleanup as m, prop as h, useEmit as g } from "@vielzeug/ore";
|
|
8
|
+
import { computed as _, signal as v, watch as y } from "@vielzeug/ripple";
|
|
9
|
+
//#region src/inputs/counter/counter.ts
|
|
10
|
+
var b = 400, x = 120, S = "ore-counter";
|
|
11
|
+
d(S, {
|
|
12
|
+
props: {
|
|
13
|
+
...s,
|
|
14
|
+
...o,
|
|
15
|
+
...a,
|
|
16
|
+
hint: h.string(),
|
|
17
|
+
label: h.string(),
|
|
18
|
+
"large-step": h.json(void 0),
|
|
19
|
+
max: h.json(void 0),
|
|
20
|
+
min: h.number(0),
|
|
21
|
+
"quick-steps": h.bool(!1),
|
|
22
|
+
readonly: h.bool(!1),
|
|
23
|
+
step: h.number(1),
|
|
24
|
+
value: h.number(0)
|
|
25
|
+
},
|
|
26
|
+
setup(e) {
|
|
27
|
+
let t = f(), n = g(), r = u("counter-label"), a = u("counter-hint"), o = v(Number(e.value.value) || 0);
|
|
28
|
+
y(e.value, (e) => {
|
|
29
|
+
let t = Number(e);
|
|
30
|
+
Number.isFinite(t) && t !== o.value && (o.value = t);
|
|
31
|
+
});
|
|
32
|
+
let s = _(() => !!e.disabled.value), c = _(() => !!e.readonly.value), d = _(() => !s.value && !c.value), h = _(() => !!e.hint.value), b = v(!1), x = null, S = i({
|
|
33
|
+
commit: (e) => {
|
|
34
|
+
if (e == null) return;
|
|
35
|
+
let r = e - o.value;
|
|
36
|
+
r !== 0 && (o.value = e, t.setAttribute("value", String(e)), n("change", {
|
|
37
|
+
delta: r,
|
|
38
|
+
value: e
|
|
39
|
+
}), x && clearTimeout(x), b.value = !1, b.value = !0, x = setTimeout(() => {
|
|
40
|
+
b.value = !1, x = null;
|
|
41
|
+
}, 200));
|
|
42
|
+
},
|
|
43
|
+
disabled: s,
|
|
44
|
+
largeStep: e["large-step"],
|
|
45
|
+
max: e.max,
|
|
46
|
+
min: e.min,
|
|
47
|
+
parse: () => o.value,
|
|
48
|
+
readonly: c,
|
|
49
|
+
step: e.step
|
|
50
|
+
}), C = () => Number(e.step.value) || 1, w = () => Number(e["large-step"].value) || C() * 10, T = _(() => !!e["quick-steps"].value), E = null, D = null, O = !1, k = () => {
|
|
51
|
+
E && clearTimeout(E), D && clearInterval(D), E = null, D = null;
|
|
52
|
+
}, A = (e, t) => {
|
|
53
|
+
d.value && t.button === 0 && (k(), O = !1, E = setTimeout(() => {
|
|
54
|
+
O = !0, S.incrementBy(e(), t), D = setInterval(() => {
|
|
55
|
+
let n = e();
|
|
56
|
+
if (n > 0 && S.atMax() || n < 0 && S.atMin()) {
|
|
57
|
+
k();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
S.incrementBy(n, t);
|
|
61
|
+
}, 120);
|
|
62
|
+
}, 400));
|
|
63
|
+
}, j = (e, t) => {
|
|
64
|
+
if (O) {
|
|
65
|
+
O = !1;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
S.incrementBy(e(), t);
|
|
69
|
+
}, M = (e) => () => e * C(), N = (e) => () => e * w(), P = (e) => () => `${e > 0 ? "+" : "−"}${w()}`;
|
|
70
|
+
m(() => {
|
|
71
|
+
k(), x && clearTimeout(x);
|
|
72
|
+
}), l({ attr: {
|
|
73
|
+
"data-bump": () => b.value ? "" : null,
|
|
74
|
+
size: e.size
|
|
75
|
+
} });
|
|
76
|
+
let F = _(() => h.value ? a : null);
|
|
77
|
+
return p`
|
|
78
|
+
<div class="counter" part="counter" role="group" aria-labelledby="${r}">
|
|
79
|
+
<div class="header" part="header">
|
|
80
|
+
<slot name="icon"></slot>
|
|
81
|
+
<span class="label" part="label" id="${r}">${() => e.label.value ?? ""}</span>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="controls" part="controls" @keydown="${(e) => S.handleKeydown(e)}">
|
|
84
|
+
<button
|
|
85
|
+
class="btn btn-large"
|
|
86
|
+
part="decrement-large-btn"
|
|
87
|
+
type="button"
|
|
88
|
+
tabindex="-1"
|
|
89
|
+
aria-label="${() => `Decrease ${e.label.value ?? ""} by ${w()}`.trim()}"
|
|
90
|
+
?hidden="${() => c.value || !T.value}"
|
|
91
|
+
?disabled="${() => !d.value || S.atMin()}"
|
|
92
|
+
@pointerdown="${(e) => A(N(-1), e)}"
|
|
93
|
+
@pointerup="${k}"
|
|
94
|
+
@pointercancel="${k}"
|
|
95
|
+
@pointerleave="${k}"
|
|
96
|
+
@click="${(e) => j(N(-1), e)}">
|
|
97
|
+
${P(-1)}
|
|
98
|
+
</button>
|
|
99
|
+
<button
|
|
100
|
+
class="btn"
|
|
101
|
+
part="decrement-btn"
|
|
102
|
+
type="button"
|
|
103
|
+
tabindex="-1"
|
|
104
|
+
aria-label="${() => `Decrease ${e.label.value ?? ""}`.trim()}"
|
|
105
|
+
?hidden="${c}"
|
|
106
|
+
?disabled="${() => !d.value || S.atMin()}"
|
|
107
|
+
@pointerdown="${(e) => A(M(-1), e)}"
|
|
108
|
+
@pointerup="${k}"
|
|
109
|
+
@pointercancel="${k}"
|
|
110
|
+
@pointerleave="${k}"
|
|
111
|
+
@click="${(e) => j(M(-1), e)}">
|
|
112
|
+
<ore-icon name="minus" size="var(--_icon-size)" stroke-width="2.5" aria-hidden="true"></ore-icon>
|
|
113
|
+
</button>
|
|
114
|
+
<output
|
|
115
|
+
class="value"
|
|
116
|
+
part="value"
|
|
117
|
+
role="spinbutton"
|
|
118
|
+
aria-live="polite"
|
|
119
|
+
aria-labelledby="${r}"
|
|
120
|
+
aria-describedby="${F}"
|
|
121
|
+
aria-valuenow="${() => String(o.value)}"
|
|
122
|
+
aria-valuemin="${() => e.min.value == null ? null : String(e.min.value)}"
|
|
123
|
+
aria-valuemax="${() => e.max.value == null ? null : String(e.max.value)}"
|
|
124
|
+
aria-readonly="${() => c.value ? "true" : null}"
|
|
125
|
+
aria-disabled="${() => s.value ? "true" : null}"
|
|
126
|
+
tabindex="${() => s.value ? "-1" : "0"}">
|
|
127
|
+
${() => String(o.value)}
|
|
128
|
+
</output>
|
|
129
|
+
<button
|
|
130
|
+
class="btn"
|
|
131
|
+
part="increment-btn"
|
|
132
|
+
type="button"
|
|
133
|
+
tabindex="-1"
|
|
134
|
+
aria-label="${() => `Increase ${e.label.value ?? ""}`.trim()}"
|
|
135
|
+
?hidden="${c}"
|
|
136
|
+
?disabled="${() => !d.value || S.atMax()}"
|
|
137
|
+
@pointerdown="${(e) => A(M(1), e)}"
|
|
138
|
+
@pointerup="${k}"
|
|
139
|
+
@pointercancel="${k}"
|
|
140
|
+
@pointerleave="${k}"
|
|
141
|
+
@click="${(e) => j(M(1), e)}">
|
|
142
|
+
<ore-icon name="plus" size="var(--_icon-size)" stroke-width="2.5" aria-hidden="true"></ore-icon>
|
|
143
|
+
</button>
|
|
144
|
+
<button
|
|
145
|
+
class="btn btn-large"
|
|
146
|
+
part="increment-large-btn"
|
|
147
|
+
type="button"
|
|
148
|
+
tabindex="-1"
|
|
149
|
+
aria-label="${() => `Increase ${e.label.value ?? ""} by ${w()}`.trim()}"
|
|
150
|
+
?hidden="${() => c.value || !T.value}"
|
|
151
|
+
?disabled="${() => !d.value || S.atMax()}"
|
|
152
|
+
@pointerdown="${(e) => A(N(1), e)}"
|
|
153
|
+
@pointerup="${k}"
|
|
154
|
+
@pointercancel="${k}"
|
|
155
|
+
@pointerleave="${k}"
|
|
156
|
+
@click="${(e) => j(N(1), e)}">
|
|
157
|
+
${P(1)}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
<slot name="hint">
|
|
161
|
+
<span class="hint" part="hint" id="${a}" ?hidden="${() => !h.value}">
|
|
162
|
+
${() => e.hint.value ?? ""}
|
|
163
|
+
</span>
|
|
164
|
+
</slot>
|
|
165
|
+
</div>
|
|
166
|
+
`;
|
|
167
|
+
},
|
|
168
|
+
shadow: { delegatesFocus: !0 },
|
|
169
|
+
styles: [
|
|
170
|
+
r,
|
|
171
|
+
n,
|
|
172
|
+
e,
|
|
173
|
+
t,
|
|
174
|
+
c
|
|
175
|
+
]
|
|
176
|
+
});
|
|
177
|
+
//#endregion
|
|
178
|
+
export { b as COUNTER_HOLD_DELAY_MS, x as COUNTER_HOLD_REPEAT_MS, S as COUNTER_TAG };
|
|
179
|
+
|
|
180
|
+
//# sourceMappingURL=counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.js","names":[],"sources":["../src/inputs/counter/counter.ts"],"sourcesContent":["import { bind, createId, define, getHost, html, onCleanup, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { createSpinnerControl } from '../../core';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport '../../content/icon/icon';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, disabledStateMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './counter.css?inline';\n\nexport type OreCounterChangeDetail = {\n /** Difference between the new and the previous value */\n delta: number;\n /** New value after clamping */\n value: number;\n};\n\nexport type OreCounterEvents = {\n change: OreCounterChangeDetail;\n};\n\n/** Counter props */\nexport type OreCounterProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** One-line timing or usage hint rendered under the controls */\n hint?: string;\n /** Visible label; also names the control for assistive technology */\n label?: string;\n /** Step for Page Up/Down (default: 10 × step) */\n 'large-step'?: number;\n /** Maximum allowed value */\n max?: number;\n /** Minimum allowed value (default: 0) */\n min?: number;\n /** Render an outer pair of −/+ buttons that move by `large-step` */\n 'quick-steps'?: boolean;\n /** Show the value without controls */\n readonly?: boolean;\n /** Component size */\n size?: ComponentSize;\n /** Increment/decrement step (default: 1) */\n step?: number;\n /** Current value */\n value?: number;\n};\n\n/** Hold delay before auto-repeat starts, then the repeat interval. */\nexport const COUNTER_HOLD_DELAY_MS = 400;\nexport const COUNTER_HOLD_REPEAT_MS = 120;\n\n/**\n * A large-target tally control for counting things at a glance: `−` / value / `+` with an\n * optional icon, label and hint. Designed for touch and arm's-length use (tabletop trackers,\n * inventories, scoreboards) rather than typed form entry — use `ore-number-input` for that.\n *\n * Holding any button auto-repeats. The value is announced through a live region and is\n * keyboard-operable as a spinbutton (Arrow keys, Home/End, Page Up/Down). Set `quick-steps` to add an\n * outer pair of buttons that move by `large-step`, for values that change in chunks (damage, scores).\n *\n * @element ore-counter\n *\n * @attr {number} value - Current value (default: 0)\n * @attr {number} min - Minimum value (default: 0)\n * @attr {number} max - Maximum value\n * @attr {number} step - Increment/decrement step (default: 1)\n * @attr {number} large-step - Step for Page Up/Down and the quick-step buttons (default: 10 × step)\n * @attr {boolean} quick-steps - Adds an outer −/+ pair that moves by `large-step`\n * @attr {boolean} disabled - Disables the control\n * @attr {boolean} readonly - Shows the value without the −/+ buttons\n * @attr {string} label - Visible label and accessible name\n * @attr {string} hint - One-line hint under the controls\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n *\n * @fires change - Fired after every accepted change. detail: { value: number, delta: number }\n *\n * @slot icon - Leading icon or token artwork shown before the label\n * @slot hint - Custom hint content (replaces the `hint` attribute)\n *\n * @cssprop --counter-value-size - Font size of the value\n * @cssprop --counter-button-size - Width/height of the −/+ buttons\n * @cssprop --counter-gap - Gap between the buttons and the value\n * @cssprop --counter-bg - Background of the control\n * @cssprop --counter-border-color - Border color of the control\n * @cssprop --counter-radius - Border radius of the control\n * @cssprop --counter-icon-size - Size of the slotted icon\n *\n * @part counter - Root container.\n * @part header - Icon and label row.\n * @part label - Label element.\n * @part controls - Buttons and value row.\n * @part decrement-large-btn - Quick-step decrement button (`quick-steps` only).\n * @part decrement-btn - Decrement button.\n * @part value - Value output.\n * @part increment-btn - Increment button.\n * @part increment-large-btn - Quick-step increment button (`quick-steps` only).\n * @part hint - Hint element.\n *\n * @example\n * ```html\n * <ore-counter label=\"Stamina\" value=\"3\" hint=\"Pay for actions\">\n * <ore-icon slot=\"icon\" name=\"zap\"></ore-icon>\n * </ore-counter>\n * <ore-counter label=\"Score\" value=\"10\" min=\"0\" max=\"99\" size=\"lg\" color=\"primary\"></ore-counter>\n * <ore-counter label=\"Damage\" value=\"12\" large-step=\"5\" quick-steps></ore-counter>\n * ```\n */\nexport const COUNTER_TAG = 'ore-counter' as const;\ndefine<OreCounterProps>(COUNTER_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n hint: prop.string(),\n label: prop.string(),\n 'large-step': prop.json(undefined as number | undefined),\n max: prop.json(undefined as number | undefined),\n min: prop.number(0),\n 'quick-steps': prop.bool(false),\n readonly: prop.bool(false),\n step: prop.number(1),\n value: prop.number(0),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCounterEvents>();\n const labelId = createId('counter-label');\n const hintId = createId('counter-hint');\n\n const current = signal(Number(props.value.value) || 0);\n\n watch(props.value, (next) => {\n const parsed = Number(next);\n\n if (Number.isFinite(parsed) && parsed !== current.value) current.value = parsed;\n });\n\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const isReadonly = computed(() => Boolean(props.readonly.value));\n const isInteractive = computed(() => !isDisabled.value && !isReadonly.value);\n const hasHint = computed(() => Boolean(props.hint.value));\n\n // Toggled briefly on every change so the CSS bump animation restarts.\n const bumped = signal(false);\n let bumpTimer: ReturnType<typeof setTimeout> | null = null;\n\n const commit = (next: number | null): void => {\n if (next == null) return;\n\n const delta = next - current.value;\n\n if (delta === 0) return;\n\n current.value = next;\n el.setAttribute('value', String(next));\n emit('change', { delta, value: next });\n\n if (bumpTimer) clearTimeout(bumpTimer);\n bumped.value = false;\n bumped.value = true;\n bumpTimer = setTimeout(() => {\n bumped.value = false;\n bumpTimer = null;\n }, 200);\n };\n\n const spinner = createSpinnerControl({\n commit,\n disabled: isDisabled,\n largeStep: props['large-step'],\n max: props.max,\n min: props.min,\n parse: () => current.value,\n readonly: isReadonly,\n step: props.step,\n });\n\n const stepSize = (): number => Number(props.step.value) || 1;\n const largeStepSize = (): number => Number(props['large-step'].value) || stepSize() * 10;\n const hasQuickSteps = computed(() => Boolean(props['quick-steps'].value));\n\n // ── Press-and-hold auto-repeat ──────────────────────────────────────────\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let repeatTimer: ReturnType<typeof setInterval> | null = null;\n let repeated = false;\n\n const stopHold = (): void => {\n if (holdTimer) clearTimeout(holdTimer);\n if (repeatTimer) clearInterval(repeatTimer);\n holdTimer = null;\n repeatTimer = null;\n };\n\n const startHold = (amount: () => number, e: PointerEvent): void => {\n if (!isInteractive.value || e.button !== 0) return;\n\n stopHold();\n repeated = false;\n holdTimer = setTimeout(() => {\n repeated = true;\n spinner.incrementBy(amount(), e);\n repeatTimer = setInterval(() => {\n const direction = amount();\n\n if ((direction > 0 && spinner.atMax()) || (direction < 0 && spinner.atMin())) {\n stopHold();\n\n return;\n }\n\n spinner.incrementBy(direction, e);\n }, COUNTER_HOLD_REPEAT_MS);\n }, COUNTER_HOLD_DELAY_MS);\n };\n\n // The click that ends a long-press must not add one more step on top of the repeats.\n const handleClick = (amount: () => number, e: Event): void => {\n if (repeated) {\n repeated = false;\n\n return;\n }\n\n spinner.incrementBy(amount(), e);\n };\n\n const small = (direction: 1 | -1) => (): number => direction * stepSize();\n const large = (direction: 1 | -1) => (): number => direction * largeStepSize();\n const quickLabel = (direction: 1 | -1) => (): string => `${direction > 0 ? '+' : '−'}${largeStepSize()}`;\n\n onCleanup(() => {\n stopHold();\n if (bumpTimer) clearTimeout(bumpTimer);\n });\n\n bind({\n attr: {\n 'data-bump': () => (bumped.value ? '' : null),\n size: props.size,\n },\n });\n\n const describedBy = computed(() => (hasHint.value ? hintId : null));\n\n return html`\n <div class=\"counter\" part=\"counter\" role=\"group\" aria-labelledby=\"${labelId}\">\n <div class=\"header\" part=\"header\">\n <slot name=\"icon\"></slot>\n <span class=\"label\" part=\"label\" id=\"${labelId}\">${() => props.label.value ?? ''}</span>\n </div>\n <div class=\"controls\" part=\"controls\" @keydown=\"${(e: KeyboardEvent) => spinner.handleKeydown(e)}\">\n <button\n class=\"btn btn-large\"\n part=\"decrement-large-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Decrease ${props.label.value ?? ''} by ${largeStepSize()}`.trim()}\"\n ?hidden=\"${() => isReadonly.value || !hasQuickSteps.value}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMin()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(large(-1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(large(-1), e)}\">\n ${quickLabel(-1)}\n </button>\n <button\n class=\"btn\"\n part=\"decrement-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Decrease ${props.label.value ?? ''}`.trim()}\"\n ?hidden=\"${isReadonly}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMin()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(small(-1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(small(-1), e)}\">\n <ore-icon name=\"minus\" size=\"var(--_icon-size)\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <output\n class=\"value\"\n part=\"value\"\n role=\"spinbutton\"\n aria-live=\"polite\"\n aria-labelledby=\"${labelId}\"\n aria-describedby=\"${describedBy}\"\n aria-valuenow=\"${() => String(current.value)}\"\n aria-valuemin=\"${() => (props.min.value != null ? String(props.min.value) : null)}\"\n aria-valuemax=\"${() => (props.max.value != null ? String(props.max.value) : null)}\"\n aria-readonly=\"${() => (isReadonly.value ? 'true' : null)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n tabindex=\"${() => (isDisabled.value ? '-1' : '0')}\">\n ${() => String(current.value)}\n </output>\n <button\n class=\"btn\"\n part=\"increment-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Increase ${props.label.value ?? ''}`.trim()}\"\n ?hidden=\"${isReadonly}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMax()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(small(1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(small(1), e)}\">\n <ore-icon name=\"plus\" size=\"var(--_icon-size)\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <button\n class=\"btn btn-large\"\n part=\"increment-large-btn\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"${() => `Increase ${props.label.value ?? ''} by ${largeStepSize()}`.trim()}\"\n ?hidden=\"${() => isReadonly.value || !hasQuickSteps.value}\"\n ?disabled=\"${() => !isInteractive.value || spinner.atMax()}\"\n @pointerdown=\"${(e: PointerEvent) => startHold(large(1), e)}\"\n @pointerup=\"${stopHold}\"\n @pointercancel=\"${stopHold}\"\n @pointerleave=\"${stopHold}\"\n @click=\"${(e: Event) => handleClick(large(1), e)}\">\n ${quickLabel(1)}\n </button>\n </div>\n <slot name=\"hint\">\n <span class=\"hint\" part=\"hint\" id=\"${hintId}\" ?hidden=\"${() => !hasHint.value}\">\n ${() => props.hint.value ?? ''}\n </span>\n </slot>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, disabledStateMixin, coarsePointerMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|