@qti-components/elements 2.0.0-next.5 → 2.0.0-next.6

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.
@@ -2,6 +2,9 @@ import { QtiFeedback } from '@qti-components/base';
2
2
  export declare class QtiFeedbackBlock extends QtiFeedback {
3
3
  static styles: import("lit").CSSResult;
4
4
  render(): import("lit").TemplateResult<1>;
5
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
6
+ protected feedbackShowing(): boolean;
7
+ protected feedbackHiding(): boolean;
5
8
  connectedCallback(): void;
6
9
  }
7
10
  declare global {
@@ -1,5 +1,6 @@
1
1
  import { css, html } from 'lit';
2
2
  import { QtiFeedback } from '@qti-components/base';
3
+ import { dispatchFeedback } from '../../internal/feedback-events';
3
4
  export class QtiFeedbackBlock extends QtiFeedback {
4
5
  static { this.styles = css `
5
6
  :host {
@@ -15,6 +16,13 @@ export class QtiFeedbackBlock extends QtiFeedback {
15
16
  render() {
16
17
  return html ` <slot part="feedback" class="feedback ${this.showStatus}"></slot> `;
17
18
  }
19
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
20
+ feedbackShowing() {
21
+ return dispatchFeedback(this, 'cito-feedback-show', 'block', this.identifier);
22
+ }
23
+ feedbackHiding() {
24
+ return dispatchFeedback(this, 'cito-feedback-hide', 'block', this.identifier);
25
+ }
18
26
  connectedCallback() {
19
27
  super.connectedCallback();
20
28
  this.checkShowFeedback(this.outcomeIdentifier);
@@ -1 +1 @@
1
- {"version":3,"file":"qti-feedback-block.js","sourceRoot":"","sources":["../../../src/components/qti-feedback-block/qti-feedback-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,OAAO,gBAAiB,SAAQ,WAAW;aAC/B,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;GAU3B,CAAC;IAEO,MAAM;QACb,OAAO,IAAI,CAAA,0CAA0C,IAAI,CAAC,UAAU,YAAY,CAAC;IACnF,CAAC;IAEe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC","sourcesContent":["import { css, html } from 'lit';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nexport class QtiFeedbackBlock extends QtiFeedback {\n static override styles = css`\n :host {\n display: block;\n }\n .on {\n display: block;\n }\n .off {\n display: none;\n }\n `;\n\n override render() {\n return html` <slot part=\"feedback\" class=\"feedback ${this.showStatus}\"></slot> `;\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.checkShowFeedback(this.outcomeIdentifier);\n }\n}\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-feedback-block': QtiFeedbackBlock;\n }\n}\n"]}
1
+ {"version":3,"file":"qti-feedback-block.js","sourceRoot":"","sources":["../../../src/components/qti-feedback-block/qti-feedback-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,OAAO,gBAAiB,SAAQ,WAAW;aAC/B,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;GAU3B,CAAC;IAEO,MAAM;QACb,OAAO,IAAI,CAAA,0CAA0C,IAAI,CAAC,UAAU,YAAY,CAAC;IACnF,CAAC;IAED,4GAA4G;IACzF,eAAe;QAChC,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChF,CAAC;IAEkB,cAAc;QAC/B,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChF,CAAC;IAEe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC","sourcesContent":["import { css, html } from 'lit';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nimport { dispatchFeedback } from '../../internal/feedback-events';\n\nexport class QtiFeedbackBlock extends QtiFeedback {\n static override styles = css`\n :host {\n display: block;\n }\n .on {\n display: block;\n }\n .off {\n display: none;\n }\n `;\n\n override render() {\n return html` <slot part=\"feedback\" class=\"feedback ${this.showStatus}\"></slot> `;\n }\n\n /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */\n protected override feedbackShowing(): boolean {\n return dispatchFeedback(this, 'cito-feedback-show', 'block', this.identifier);\n }\n\n protected override feedbackHiding(): boolean {\n return dispatchFeedback(this, 'cito-feedback-hide', 'block', this.identifier);\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.checkShowFeedback(this.outcomeIdentifier);\n }\n}\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-feedback-block': QtiFeedbackBlock;\n }\n}\n"]}
@@ -2,6 +2,9 @@ import { QtiFeedback } from '@qti-components/base';
2
2
  export declare class QtiFeedbackInline extends QtiFeedback {
3
3
  static styles: import("lit").CSSResult;
4
4
  render: () => import("lit").TemplateResult<1>;
5
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
6
+ protected feedbackShowing(): boolean;
7
+ protected feedbackHiding(): boolean;
5
8
  connectedCallback(): void;
6
9
  }
7
10
  declare global {
@@ -1,6 +1,7 @@
1
1
  import { css, html } from 'lit';
2
2
  import { ifDefined } from 'lit/directives/if-defined.js';
3
3
  import { QtiFeedback } from '@qti-components/base';
4
+ import { dispatchFeedback } from '../../internal/feedback-events';
4
5
  export class QtiFeedbackInline extends QtiFeedback {
5
6
  constructor() {
6
7
  super(...arguments);
@@ -14,6 +15,13 @@ export class QtiFeedbackInline extends QtiFeedback {
14
15
  display: none;
15
16
  }
16
17
  `; }
18
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
19
+ feedbackShowing() {
20
+ return dispatchFeedback(this, 'cito-feedback-show', 'inline', this.identifier);
21
+ }
22
+ feedbackHiding() {
23
+ return dispatchFeedback(this, 'cito-feedback-hide', 'inline', this.identifier);
24
+ }
17
25
  connectedCallback() {
18
26
  super.connectedCallback();
19
27
  this.checkShowFeedback(this.outcomeIdentifier);
@@ -1 +1 @@
1
- {"version":3,"file":"qti-feedback-inline.js","sourceRoot":"","sources":["../../../src/components/qti-feedback-inline/qti-feedback-inline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAAlD;;QAUW,WAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAA,iCAAiC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;IAMtG,CAAC;aAfiB,WAAM,GAAG,GAAG,CAAA;;;;;;;GAO3B,AAPqB,CAOpB;IAIc,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC","sourcesContent":["import { css, html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nexport class QtiFeedbackInline extends QtiFeedback {\n static override styles = css`\n .on {\n display: inline-block;\n }\n .off {\n display: none;\n }\n `;\n\n override render = () => html` <slot part=\"feedback\" class=\"${ifDefined(this.showStatus)}\"></slot> `;\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.checkShowFeedback(this.outcomeIdentifier);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-feedback-inline': QtiFeedbackInline;\n }\n}\n"]}
1
+ {"version":3,"file":"qti-feedback-inline.js","sourceRoot":"","sources":["../../../src/components/qti-feedback-inline/qti-feedback-inline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAAlD;;QAUW,WAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAA,iCAAiC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;IAetG,CAAC;aAxBiB,WAAM,GAAG,GAAG,CAAA;;;;;;;GAO3B,AAPqB,CAOpB;IAIF,4GAA4G;IACzF,eAAe;QAChC,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACjF,CAAC;IAEkB,cAAc;QAC/B,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACjF,CAAC;IAEe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC","sourcesContent":["import { css, html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nimport { dispatchFeedback } from '../../internal/feedback-events';\n\nexport class QtiFeedbackInline extends QtiFeedback {\n static override styles = css`\n .on {\n display: inline-block;\n }\n .off {\n display: none;\n }\n `;\n\n override render = () => html` <slot part=\"feedback\" class=\"${ifDefined(this.showStatus)}\"></slot> `;\n\n /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */\n protected override feedbackShowing(): boolean {\n return dispatchFeedback(this, 'cito-feedback-show', 'inline', this.identifier);\n }\n\n protected override feedbackHiding(): boolean {\n return dispatchFeedback(this, 'cito-feedback-hide', 'inline', this.identifier);\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.checkShowFeedback(this.outcomeIdentifier);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-feedback-inline': QtiFeedbackInline;\n }\n}\n"]}
@@ -4,6 +4,9 @@ export declare class QtiModalFeedback extends QtiFeedback {
4
4
  render(): import("lit").TemplateResult<1>;
5
5
  openFeedback(): void;
6
6
  closeFeedback(): void;
7
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
8
+ protected feedbackShowing(): boolean;
9
+ protected feedbackHiding(): boolean;
7
10
  connectedCallback(): void;
8
11
  protected updated(changedProperties: Map<string | number | symbol, unknown>): void;
9
12
  }
@@ -1,5 +1,6 @@
1
1
  import { css, html } from 'lit';
2
2
  import { QtiFeedback } from '@qti-components/base';
3
+ import { dispatchFeedback } from '../../internal/feedback-events';
3
4
  export class QtiModalFeedback extends QtiFeedback {
4
5
  static { this.styles = css `
5
6
  .cito-dialog {
@@ -63,6 +64,13 @@ export class QtiModalFeedback extends QtiFeedback {
63
64
  this.showStatus = 'off';
64
65
  }
65
66
  }
67
+ /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */
68
+ feedbackShowing() {
69
+ return dispatchFeedback(this, 'cito-feedback-show', 'modal', this.identifier);
70
+ }
71
+ feedbackHiding() {
72
+ return dispatchFeedback(this, 'cito-feedback-hide', 'modal', this.identifier);
73
+ }
66
74
  connectedCallback() {
67
75
  super.connectedCallback();
68
76
  if (this.showStatus === 'on') {
@@ -1 +1 @@
1
- {"version":3,"file":"qti-modal-feedback.js","sourceRoot":"","sources":["../../../src/components/qti-modal-feedback/qti-modal-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,OAAO,gBAAiB,SAAQ,WAAW;aAC/B,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsC3B,CAAC;IAEO,MAAM;QACb,OAAO,IAAI,CAAA;2DAC4C,IAAI,CAAC,UAAU,KAAK,IAAI;;;wDAG3B,IAAI,CAAC,aAAa;;;KAGrE,CAAC;IACJ,CAAC;IAED,YAAY;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAA6B,CAAC;QACpF,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC3B,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,aAAa;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAA6B,CAAC;QACpF,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IAEe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAEkB,OAAO,CAAC,iBAAyD;QAClF,IAAI,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC","sourcesContent":["import { css, html } from 'lit';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nexport class QtiModalFeedback extends QtiFeedback {\n static override styles = css`\n .cito-dialog {\n background: var(--qti-bg);\n border: var(--qti-border-thickness) var(--qti-border-style) var(--qti-border-color);\n border-radius: var(--qti-border-radius);\n padding: var(--qti-padding-box);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1000;\n width: auto;\n max-width: 90%;\n }\n\n .button {\n border-radius: var(--qti-border-radius);\n padding: var(--qti-padding-box);\n background-color: var(--qti-bg-active);\n border: var(--qti-border-active);\n cursor: pointer;\n position: relative;\n display: inline-block;\n }\n\n /* Inlined from --qti-disabled-bg / --qti-disabled-color, which this button was the only reader\n of anywhere in the repo. They were named as a global disabled vocabulary but no interaction\n ever used them: the theme's disabled treatment is cursor only (see the note in qti-mixins.css). */\n .button:disabled {\n background-color: transparent;\n color: var(--qti-fg);\n cursor: not-allowed;\n }\n\n .button:focus {\n outline: var(--qti-focus-border-width) solid var(--qti-focus-color);\n }\n `;\n\n override render() {\n return html`\n <dialog class=\"cito-dialog\" part=\"feedback\" ?open=\"${this.showStatus === 'on'}\">\n <slot></slot>\n <div style=\"margin-top: var(--qti-gap); text-align: center;\">\n <button class=\"button close-button\" @click=\"${this.closeFeedback}\">Close</button>\n </div>\n </dialog>\n `;\n }\n\n openFeedback() {\n const dialog = this.shadowRoot?.querySelector('dialog') as HTMLDialogElement | null;\n if (dialog && !dialog.open) {\n dialog.showModal();\n }\n }\n\n closeFeedback() {\n const dialog = this.shadowRoot?.querySelector('dialog') as HTMLDialogElement | null;\n if (dialog && dialog.open) {\n dialog.close();\n this.showStatus = 'off';\n }\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n if (this.showStatus === 'on') {\n this.openFeedback();\n }\n }\n\n protected override updated(changedProperties: Map<string | number | symbol, unknown>): void {\n if (changedProperties.has('showStatus')) {\n if (this.showStatus === 'on') {\n this.openFeedback();\n } else {\n this.closeFeedback();\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-modal-feedback': QtiModalFeedback;\n }\n}\n"]}
1
+ {"version":3,"file":"qti-modal-feedback.js","sourceRoot":"","sources":["../../../src/components/qti-modal-feedback/qti-modal-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,OAAO,gBAAiB,SAAQ,WAAW;aAC/B,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsC3B,CAAC;IAEO,MAAM;QACb,OAAO,IAAI,CAAA;2DAC4C,IAAI,CAAC,UAAU,KAAK,IAAI;;;wDAG3B,IAAI,CAAC,aAAa;;;KAGrE,CAAC;IACJ,CAAC;IAED,YAAY;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAA6B,CAAC;QACpF,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC3B,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,aAAa;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAA6B,CAAC;QACpF,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,4GAA4G;IACzF,eAAe;QAChC,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChF,CAAC;IAEkB,cAAc;QAC/B,OAAO,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChF,CAAC;IAEe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAEkB,OAAO,CAAC,iBAAyD;QAClF,IAAI,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC","sourcesContent":["import { css, html } from 'lit';\n\nimport { QtiFeedback } from '@qti-components/base';\n\nimport { dispatchFeedback } from '../../internal/feedback-events';\n\nexport class QtiModalFeedback extends QtiFeedback {\n static override styles = css`\n .cito-dialog {\n background: var(--qti-bg);\n border: var(--qti-border-thickness) var(--qti-border-style) var(--qti-border-color);\n border-radius: var(--qti-border-radius);\n padding: var(--qti-padding-box);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1000;\n width: auto;\n max-width: 90%;\n }\n\n .button {\n border-radius: var(--qti-border-radius);\n padding: var(--qti-padding-box);\n background-color: var(--qti-bg-active);\n border: var(--qti-border-active);\n cursor: pointer;\n position: relative;\n display: inline-block;\n }\n\n /* Inlined from --qti-disabled-bg / --qti-disabled-color, which this button was the only reader\n of anywhere in the repo. They were named as a global disabled vocabulary but no interaction\n ever used them: the theme's disabled treatment is cursor only (see the note in qti-mixins.css). */\n .button:disabled {\n background-color: transparent;\n color: var(--qti-fg);\n cursor: not-allowed;\n }\n\n .button:focus {\n outline: var(--qti-focus-border-width) solid var(--qti-focus-color);\n }\n `;\n\n override render() {\n return html`\n <dialog class=\"cito-dialog\" part=\"feedback\" ?open=\"${this.showStatus === 'on'}\">\n <slot></slot>\n <div style=\"margin-top: var(--qti-gap); text-align: center;\">\n <button class=\"button close-button\" @click=\"${this.closeFeedback}\">Close</button>\n </div>\n </dialog>\n `;\n }\n\n openFeedback() {\n const dialog = this.shadowRoot?.querySelector('dialog') as HTMLDialogElement | null;\n if (dialog && !dialog.open) {\n dialog.showModal();\n }\n }\n\n closeFeedback() {\n const dialog = this.shadowRoot?.querySelector('dialog') as HTMLDialogElement | null;\n if (dialog && dialog.open) {\n dialog.close();\n this.showStatus = 'off';\n }\n }\n\n /** `cito-feedback-show`: a listener that calls `preventDefault()` keeps this hidden and shows it itself. */\n protected override feedbackShowing(): boolean {\n return dispatchFeedback(this, 'cito-feedback-show', 'modal', this.identifier);\n }\n\n protected override feedbackHiding(): boolean {\n return dispatchFeedback(this, 'cito-feedback-hide', 'modal', this.identifier);\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n if (this.showStatus === 'on') {\n this.openFeedback();\n }\n }\n\n protected override updated(changedProperties: Map<string | number | symbol, unknown>): void {\n if (changedProperties.has('showStatus')) {\n if (this.showStatus === 'on') {\n this.openFeedback();\n } else {\n this.closeFeedback();\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-modal-feedback': QtiModalFeedback;\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { FeedbackEventDetail } from '../public-events';
2
+ interface FeedbackElement extends Element {
3
+ outcomeIdentifier: string;
4
+ }
5
+ /**
6
+ * Send `cito-feedback-show` or `cito-feedback-hide` from a feedback element, just before it shows or
7
+ * hides. Both are cancelable; this returns `false` when the host cancels, i.e. takes over.
8
+ */
9
+ export declare function dispatchFeedback(element: FeedbackElement, name: 'cito-feedback-show' | 'cito-feedback-hide', kind: FeedbackEventDetail['kind'], identifier: string): boolean;
10
+ export {};
@@ -0,0 +1,17 @@
1
+ import { dispatchPublic } from '../public-events';
2
+ /**
3
+ * Send `cito-feedback-show` or `cito-feedback-hide` from a feedback element, just before it shows or
4
+ * hides. Both are cancelable; this returns `false` when the host cancels, i.e. takes over.
5
+ */
6
+ export function dispatchFeedback(element, name, kind, identifier) {
7
+ const itemIdentifier = element.closest('qti-assessment-item')?.getAttribute('identifier') ?? undefined;
8
+ const detail = {
9
+ kind,
10
+ identifier,
11
+ outcomeIdentifier: element.outcomeIdentifier,
12
+ element,
13
+ ...(itemIdentifier ? { itemIdentifier } : {})
14
+ };
15
+ return dispatchPublic(element, name, detail, true);
16
+ }
17
+ //# sourceMappingURL=feedback-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-events.js","sourceRoot":"","sources":["../../src/internal/feedback-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQlD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAwB,EACxB,IAAiD,EACjD,IAAiC,EACjC,UAAkB;IAElB,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC;IACvG,MAAM,MAAM,GAAwB;QAClC,IAAI;QACJ,UAAU;QACV,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,OAAO;QACP,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAC;IACF,OAAO,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import { dispatchPublic } from '../public-events';\n\nimport type { FeedbackEventDetail } from '../public-events';\n\ninterface FeedbackElement extends Element {\n outcomeIdentifier: string;\n}\n\n/**\n * Send `cito-feedback-show` or `cito-feedback-hide` from a feedback element, just before it shows or\n * hides. Both are cancelable; this returns `false` when the host cancels, i.e. takes over.\n */\nexport function dispatchFeedback(\n element: FeedbackElement,\n name: 'cito-feedback-show' | 'cito-feedback-hide',\n kind: FeedbackEventDetail['kind'],\n identifier: string\n): boolean {\n const itemIdentifier = element.closest('qti-assessment-item')?.getAttribute('identifier') ?? undefined;\n const detail: FeedbackEventDetail = {\n kind,\n identifier,\n outcomeIdentifier: element.outcomeIdentifier,\n element,\n ...(itemIdentifier ? { itemIdentifier } : {})\n };\n return dispatchPublic(element, name, detail, true);\n}\n"]}
@@ -18,6 +18,18 @@ export interface RubricPlacement {
18
18
  className: string;
19
19
  element: Element;
20
20
  }
21
+ /** The detail of `cito-feedback-show` and `cito-feedback-hide`. */
22
+ export interface FeedbackEventDetail {
23
+ kind: 'block' | 'inline' | 'modal';
24
+ /** The feedback's `identifier`. */
25
+ identifier: string;
26
+ /** The outcome it follows (`outcome-identifier`). */
27
+ outcomeIdentifier: string;
28
+ /** The feedback element itself: read or clone its content (it stays in the DOM, hidden). */
29
+ element: Element;
30
+ /** The identifier of the item it is in, when it is in one. */
31
+ itemIdentifier?: string;
32
+ }
21
33
  export interface PublicItemEventMap {
22
34
  'cito-item-response-changed': CustomEvent<InteractionChangedDetails>;
23
35
  /**
@@ -31,6 +43,13 @@ export interface PublicItemEventMap {
31
43
  'cito-item-outcomes-changed': CustomEvent<OutcomesChangedDetails>;
32
44
  /** Cancelable: `preventDefault()` keeps the rubric block where it is. */
33
45
  'cito-item-rubric-placement': CustomEvent<RubricPlacement>;
46
+ /**
47
+ * Cancelable: the feedback element is about to show (its condition turned true). `preventDefault()`
48
+ * keeps it hidden, so the host can show the content itself. Sent once per showing.
49
+ */
50
+ 'cito-feedback-show': CustomEvent<FeedbackEventDetail>;
51
+ /** The condition of a feedback that was shown (or taken over by the host) turned false again. */
52
+ 'cito-feedback-hide': CustomEvent<FeedbackEventDetail>;
34
53
  }
35
54
  export type PublicItemEventName = keyof PublicItemEventMap;
36
55
  export declare const PUBLIC_ITEM_EVENTS: Record<PublicItemEventName, PublicEventDeclaration>;
@@ -9,7 +9,9 @@ export const PUBLIC_ITEM_EVENTS = {
9
9
  kind: 'notification',
10
10
  scope: 'item',
11
11
  deprecated: 'qti-rubric:discretionary-placement'
12
- }
12
+ },
13
+ 'cito-feedback-show': { kind: 'notification', scope: 'item' },
14
+ 'cito-feedback-hide': { kind: 'notification', scope: 'item' }
13
15
  };
14
16
  /**
15
17
  * Dispatch `name` and its deprecated name with the same `detail` object, new name first. Returns
@@ -1 +1 @@
1
- {"version":3,"file":"public-events.js","sourceRoot":"","sources":["../src/public-events.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n InteractionChangedDetails,\n OutcomeChangedDetails,\n OutcomesChangedDetails,\n SetOutcomesDetails\n} from './internal/event-types';\n\n/**\n * The public events of the item. The name tells you it is public: everything declared here starts\n * with `cito-`; every other event is internal plumbing and may change in any release.\n *\n * Requests are verbs, notifications are past tense. All bubble and are composed.\n *\n * `deprecated` is the name the event had before it became public. `dispatchPublic` sends and\n * `listenPublic` handles both until the next major, then the field goes.\n */\nexport interface PublicEventDeclaration {\n kind: 'request' | 'notification';\n scope: 'test' | 'item';\n /** The name before it was public. Dispatched and handled alongside the new one. */\n deprecated?: string;\n}\n\nexport interface RubricPlacement {\n className: string;\n element: Element;\n}\n\nexport interface PublicItemEventMap {\n // `cito-item-rendered` (detail: the `QtiAssessmentItem`) is added by qti-assessment-item.ts, so this\n // module imports no element: that import would be a cycle.\n 'cito-item-response-changed': CustomEvent<InteractionChangedDetails>;\n /**\n * Request: the item applies these outcomes in one update. Response processing sends it; a host\n * that scores on a backend sends it on the item with the outcomes the backend returned.\n */\n 'cito-item-set-outcomes': CustomEvent<SetOutcomesDetails>;\n /** One per outcome an update applied, with its final value, after the item context is published. */\n 'cito-item-outcome-changed': CustomEvent<OutcomeChangedDetails>;\n /** All the outcomes one update applied, after the item context is published. */\n 'cito-item-outcomes-changed': CustomEvent<OutcomesChangedDetails>;\n /** Cancelable: `preventDefault()` keeps the rubric block where it is. */\n 'cito-item-rubric-placement': CustomEvent<RubricPlacement>;\n}\n\nexport type PublicItemEventName = keyof PublicItemEventMap;\n\nexport const PUBLIC_ITEM_EVENTS: Record<PublicItemEventName, PublicEventDeclaration> = {\n // The old name `qti-assessment-item-connected` stays as internal plumbing: it is sent separately.\n 'cito-item-rendered': { kind: 'notification', scope: 'item' },\n 'cito-item-response-changed': { kind: 'notification', scope: 'item', deprecated: 'qti-interaction-changed' },\n 'cito-item-set-outcomes': { kind: 'request', scope: 'item' },\n 'cito-item-outcome-changed': { kind: 'notification', scope: 'item', deprecated: 'qti-outcome-changed' },\n 'cito-item-outcomes-changed': { kind: 'notification', scope: 'item' },\n 'cito-item-rubric-placement': {\n kind: 'notification',\n scope: 'item',\n deprecated: 'qti-rubric:discretionary-placement'\n }\n};\n\ndeclare global {\n interface HTMLElementEventMap extends PublicItemEventMap {}\n}\n\n/**\n * Dispatch `name` and its deprecated name with the same `detail` object, new name first. Returns\n * `false` when a listener of either cancelled the event. The detail is always an object.\n * Shared by the item and test tiers; use `dispatchPublic` (item) or the test's own wrapper.\n */\nexport function dispatchDeclared(\n target: EventTarget,\n declarations: Record<string, PublicEventDeclaration>,\n name: string,\n detail: unknown,\n cancelable = false\n): boolean {\n const init = { detail: detail ?? {}, bubbles: true, composed: true, cancelable };\n const notCancelled = target.dispatchEvent(new CustomEvent(name, init));\n const { deprecated } = declarations[name];\n if (!deprecated) return notCancelled;\n return target.dispatchEvent(new CustomEvent(deprecated, init)) && notCancelled;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Listen for `name` and its deprecated name. `dispatchDeclared` sends the old name straight after\n * the new one, synchronously, with the same `detail`: that one is skipped, so the handler runs\n * once. A host that sends only the old name is handled too, and warned once per name in the\n * console: only a sender outside our own components gets here without the new name before it.\n */\nexport function listenDeclared(\n target: EventTarget,\n declarations: Record<string, PublicEventDeclaration>,\n name: string,\n handler: (e: Event) => void\n): void {\n let justHandled: unknown;\n target.addEventListener(name, e => {\n justHandled = (e as CustomEvent).detail;\n queueMicrotask(() => (justHandled = undefined));\n handler(e);\n });\n const { deprecated } = declarations[name];\n if (deprecated) {\n target.addEventListener(deprecated, e => {\n if (justHandled !== undefined && (e as CustomEvent).detail === justHandled) return;\n if (!warned.has(deprecated)) {\n warned.add(deprecated);\n console.warn(`[qti-components] The event \"${deprecated}\" is deprecated; dispatch \"${name}\" instead.`);\n }\n handler(e);\n });\n }\n}\n\nexport function dispatchPublic<K extends PublicItemEventName>(\n target: EventTarget,\n name: K,\n detail: PublicItemEventMap[K] extends CustomEvent<infer D> ? D : never,\n cancelable = false\n): boolean {\n return dispatchDeclared(target, PUBLIC_ITEM_EVENTS, name, detail, cancelable);\n}\n\nexport function listenPublic<K extends PublicItemEventName>(\n target: EventTarget,\n name: K,\n handler: (e: PublicItemEventMap[K]) => void\n): void {\n listenDeclared(target, PUBLIC_ITEM_EVENTS, name, handler as (e: Event) => void);\n}\n"]}
1
+ {"version":3,"file":"public-events.js","sourceRoot":"","sources":["../src/public-events.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n InteractionChangedDetails,\n OutcomeChangedDetails,\n OutcomesChangedDetails,\n SetOutcomesDetails\n} from './internal/event-types';\n\n/**\n * The public events of the item. The name tells you it is public: everything declared here starts\n * with `cito-`; every other event is internal plumbing and may change in any release.\n *\n * Requests are verbs, notifications are past tense. All bubble and are composed.\n *\n * `deprecated` is the name the event had before it became public. `dispatchPublic` sends and\n * `listenPublic` handles both until the next major, then the field goes.\n */\nexport interface PublicEventDeclaration {\n kind: 'request' | 'notification';\n scope: 'test' | 'item';\n /** The name before it was public. Dispatched and handled alongside the new one. */\n deprecated?: string;\n}\n\nexport interface RubricPlacement {\n className: string;\n element: Element;\n}\n\n/** The detail of `cito-feedback-show` and `cito-feedback-hide`. */\nexport interface FeedbackEventDetail {\n kind: 'block' | 'inline' | 'modal';\n /** The feedback's `identifier`. */\n identifier: string;\n /** The outcome it follows (`outcome-identifier`). */\n outcomeIdentifier: string;\n /** The feedback element itself: read or clone its content (it stays in the DOM, hidden). */\n element: Element;\n /** The identifier of the item it is in, when it is in one. */\n itemIdentifier?: string;\n}\n\nexport interface PublicItemEventMap {\n // `cito-item-rendered` (detail: the `QtiAssessmentItem`) is added by qti-assessment-item.ts, so this\n // module imports no element: that import would be a cycle.\n 'cito-item-response-changed': CustomEvent<InteractionChangedDetails>;\n /**\n * Request: the item applies these outcomes in one update. Response processing sends it; a host\n * that scores on a backend sends it on the item with the outcomes the backend returned.\n */\n 'cito-item-set-outcomes': CustomEvent<SetOutcomesDetails>;\n /** One per outcome an update applied, with its final value, after the item context is published. */\n 'cito-item-outcome-changed': CustomEvent<OutcomeChangedDetails>;\n /** All the outcomes one update applied, after the item context is published. */\n 'cito-item-outcomes-changed': CustomEvent<OutcomesChangedDetails>;\n /** Cancelable: `preventDefault()` keeps the rubric block where it is. */\n 'cito-item-rubric-placement': CustomEvent<RubricPlacement>;\n /**\n * Cancelable: the feedback element is about to show (its condition turned true). `preventDefault()`\n * keeps it hidden, so the host can show the content itself. Sent once per showing.\n */\n 'cito-feedback-show': CustomEvent<FeedbackEventDetail>;\n /** The condition of a feedback that was shown (or taken over by the host) turned false again. */\n 'cito-feedback-hide': CustomEvent<FeedbackEventDetail>;\n}\n\nexport type PublicItemEventName = keyof PublicItemEventMap;\n\nexport const PUBLIC_ITEM_EVENTS: Record<PublicItemEventName, PublicEventDeclaration> = {\n // The old name `qti-assessment-item-connected` stays as internal plumbing: it is sent separately.\n 'cito-item-rendered': { kind: 'notification', scope: 'item' },\n 'cito-item-response-changed': { kind: 'notification', scope: 'item', deprecated: 'qti-interaction-changed' },\n 'cito-item-set-outcomes': { kind: 'request', scope: 'item' },\n 'cito-item-outcome-changed': { kind: 'notification', scope: 'item', deprecated: 'qti-outcome-changed' },\n 'cito-item-outcomes-changed': { kind: 'notification', scope: 'item' },\n 'cito-item-rubric-placement': {\n kind: 'notification',\n scope: 'item',\n deprecated: 'qti-rubric:discretionary-placement'\n },\n 'cito-feedback-show': { kind: 'notification', scope: 'item' },\n 'cito-feedback-hide': { kind: 'notification', scope: 'item' }\n};\n\ndeclare global {\n interface HTMLElementEventMap extends PublicItemEventMap {}\n}\n\n/**\n * Dispatch `name` and its deprecated name with the same `detail` object, new name first. Returns\n * `false` when a listener of either cancelled the event. The detail is always an object.\n * Shared by the item and test tiers; use `dispatchPublic` (item) or the test's own wrapper.\n */\nexport function dispatchDeclared(\n target: EventTarget,\n declarations: Record<string, PublicEventDeclaration>,\n name: string,\n detail: unknown,\n cancelable = false\n): boolean {\n const init = { detail: detail ?? {}, bubbles: true, composed: true, cancelable };\n const notCancelled = target.dispatchEvent(new CustomEvent(name, init));\n const { deprecated } = declarations[name];\n if (!deprecated) return notCancelled;\n return target.dispatchEvent(new CustomEvent(deprecated, init)) && notCancelled;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Listen for `name` and its deprecated name. `dispatchDeclared` sends the old name straight after\n * the new one, synchronously, with the same `detail`: that one is skipped, so the handler runs\n * once. A host that sends only the old name is handled too, and warned once per name in the\n * console: only a sender outside our own components gets here without the new name before it.\n */\nexport function listenDeclared(\n target: EventTarget,\n declarations: Record<string, PublicEventDeclaration>,\n name: string,\n handler: (e: Event) => void\n): void {\n let justHandled: unknown;\n target.addEventListener(name, e => {\n justHandled = (e as CustomEvent).detail;\n queueMicrotask(() => (justHandled = undefined));\n handler(e);\n });\n const { deprecated } = declarations[name];\n if (deprecated) {\n target.addEventListener(deprecated, e => {\n if (justHandled !== undefined && (e as CustomEvent).detail === justHandled) return;\n if (!warned.has(deprecated)) {\n warned.add(deprecated);\n console.warn(`[qti-components] The event \"${deprecated}\" is deprecated; dispatch \"${name}\" instead.`);\n }\n handler(e);\n });\n }\n}\n\nexport function dispatchPublic<K extends PublicItemEventName>(\n target: EventTarget,\n name: K,\n detail: PublicItemEventMap[K] extends CustomEvent<infer D> ? D : never,\n cancelable = false\n): boolean {\n return dispatchDeclared(target, PUBLIC_ITEM_EVENTS, name, detail, cancelable);\n}\n\nexport function listenPublic<K extends PublicItemEventName>(\n target: EventTarget,\n name: K,\n handler: (e: PublicItemEventMap[K]) => void\n): void {\n listenDeclared(target, PUBLIC_ITEM_EVENTS, name, handler as (e: Event) => void);\n}\n"]}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@qti-components/elements",
3
3
  "description": "QTI elements utilities",
4
- "version": "2.0.0-next.5",
4
+ "version": "2.0.0-next.6",
5
5
  "author": "",
6
6
  "dependencies": {
7
- "@qti-components/base": "^3.0.0-next.4",
8
- "@qti-components/transformers": "^1.7.3",
7
+ "@qti-components/base": "^3.0.0-next.5",
8
+ "@qti-components/transformers": "^1.8.0-next.0",
9
9
  "@qti-components/utilities": "^1.3.3"
10
10
  },
11
11
  "devDependencies": {